mirror of
https://github.com/mudler/LocalAI.git
synced 2026-01-07 11:10:11 -06:00
chore: refactor css, restyle to be slightly minimalistic (#7397)
restyle Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
committed by
GitHub
parent
468ac608f3
commit
54b5dfa8e1
247
core/http/static/animations.css
Normal file
247
core/http/static/animations.css
Normal file
@@ -0,0 +1,247 @@
|
||||
/* LocalAI Animation System */
|
||||
/* Purposeful animations with performance optimization */
|
||||
|
||||
/* Animation Keyframes */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cardReveal {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 8px rgba(56, 189, 248, 0.15);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 12px rgba(56, 189, 248, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* P2P/Network Specific Animations */
|
||||
@keyframes rotateCircleNodes {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes shakeFlask {
|
||||
0%, 10% { transform: rotate(0deg); }
|
||||
20% { transform: rotate(-10deg); }
|
||||
30% { transform: rotate(10deg); }
|
||||
40% { transform: rotate(-8deg); }
|
||||
50% { transform: rotate(8deg); }
|
||||
60% { transform: rotate(-5deg); }
|
||||
70% { transform: rotate(5deg); }
|
||||
80% { transform: rotate(-2deg); }
|
||||
90% { transform: rotate(2deg); }
|
||||
100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
@keyframes nodeGlow {
|
||||
0% { left: -100%; }
|
||||
50% { left: 100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
/* Animation Utility Classes */
|
||||
.fade-in {
|
||||
animation: fadeIn var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
/* Transition Utility Classes */
|
||||
.transition-default {
|
||||
transition: all var(--duration-fast) var(--ease-default);
|
||||
}
|
||||
|
||||
.transition-color {
|
||||
transition: color var(--duration-fast) var(--ease-default);
|
||||
}
|
||||
|
||||
.transition-background {
|
||||
transition: background-color var(--duration-fast) var(--ease-default);
|
||||
}
|
||||
|
||||
.fade-in-up {
|
||||
animation: fadeInUp var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
.fade-in-down {
|
||||
animation: fadeInDown var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
.slide-in-right {
|
||||
animation: slideInRight var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
.slide-in-left {
|
||||
animation: slideInLeft var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
.scale-in {
|
||||
animation: scaleIn var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
/* Staggered Card Animations */
|
||||
.card-animate {
|
||||
animation: cardReveal var(--duration-normal) var(--ease-out) backwards;
|
||||
}
|
||||
|
||||
.card-animate:nth-child(1) { animation-delay: 0ms; }
|
||||
.card-animate:nth-child(2) { animation-delay: 50ms; }
|
||||
.card-animate:nth-child(3) { animation-delay: 100ms; }
|
||||
.card-animate:nth-child(4) { animation-delay: 150ms; }
|
||||
.card-animate:nth-child(5) { animation-delay: 200ms; }
|
||||
.card-animate:nth-child(6) { animation-delay: 250ms; }
|
||||
.card-animate:nth-child(7) { animation-delay: 300ms; }
|
||||
.card-animate:nth-child(8) { animation-delay: 350ms; }
|
||||
.card-animate:nth-child(9) { animation-delay: 400ms; }
|
||||
.card-animate:nth-child(10) { animation-delay: 450ms; }
|
||||
.card-animate:nth-child(11) { animation-delay: 500ms; }
|
||||
.card-animate:nth-child(12) { animation-delay: 550ms; }
|
||||
|
||||
/* Hero Text Animation */
|
||||
.hero-title {
|
||||
animation: fadeInUp var(--duration-normal) var(--ease-out) backwards;
|
||||
animation-delay: 50ms;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
animation: fadeInUp var(--duration-normal) var(--ease-out) backwards;
|
||||
animation-delay: 100ms;
|
||||
}
|
||||
|
||||
/* Navigation Animation */
|
||||
.nav-fade-in {
|
||||
animation: fadeIn var(--duration-normal) var(--ease-out) backwards;
|
||||
animation-delay: 0ms;
|
||||
}
|
||||
|
||||
/* Loading States - Minimal */
|
||||
.pulse-animation {
|
||||
animation: pulse 1.5s var(--ease-in-out) infinite;
|
||||
}
|
||||
|
||||
.glow-animation {
|
||||
animation: glow 1.5s var(--ease-in-out) infinite;
|
||||
}
|
||||
|
||||
/* Reduced Motion Support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
.card-animate,
|
||||
.fade-in-up,
|
||||
.fade-in-down,
|
||||
.slide-in-right,
|
||||
.slide-in-left,
|
||||
.scale-in,
|
||||
.hero-title,
|
||||
.hero-subtitle {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance Optimization */
|
||||
.card-animate,
|
||||
.fade-in-up,
|
||||
.fade-in-down,
|
||||
.slide-in-right,
|
||||
.slide-in-left,
|
||||
.scale-in {
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
/* After animation completes, remove will-change */
|
||||
.card-animate.animation-complete,
|
||||
.fade-in-up.animation-complete,
|
||||
.fade-in-down.animation-complete,
|
||||
.slide-in-right.animation-complete,
|
||||
.slide-in-left.animation-complete,
|
||||
.scale-in.animation-complete {
|
||||
will-change: auto;
|
||||
}
|
||||
|
||||
BIN
core/http/static/assets/jetbrains-mono-medium.ttf
Normal file
BIN
core/http/static/assets/jetbrains-mono-medium.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/jetbrains-mono-regular.ttf
Normal file
BIN
core/http/static/assets/jetbrains-mono-regular.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/jetbrains-mono-semibold.ttf
Normal file
BIN
core/http/static/assets/jetbrains-mono-semibold.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/playfair-display-bold.ttf
Normal file
BIN
core/http/static/assets/playfair-display-bold.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/playfair-display-regular.ttf
Normal file
BIN
core/http/static/assets/playfair-display-regular.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/playfair-display-semibold.ttf
Normal file
BIN
core/http/static/assets/playfair-display-semibold.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/space-grotesk-bold.ttf
Normal file
BIN
core/http/static/assets/space-grotesk-bold.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/space-grotesk-medium.ttf
Normal file
BIN
core/http/static/assets/space-grotesk-medium.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/space-grotesk-regular.ttf
Normal file
BIN
core/http/static/assets/space-grotesk-regular.ttf
Normal file
Binary file not shown.
BIN
core/http/static/assets/space-grotesk-semibold.ttf
Normal file
BIN
core/http/static/assets/space-grotesk-semibold.ttf
Normal file
Binary file not shown.
441
core/http/static/components.css
Normal file
441
core/http/static/components.css
Normal file
@@ -0,0 +1,441 @@
|
||||
/* LocalAI Component Styles */
|
||||
/* Buttons, Cards, Inputs, Grid Pattern, Hero Sections */
|
||||
|
||||
/* ============================================
|
||||
Grid Pattern
|
||||
============================================ */
|
||||
.grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(rgba(56, 189, 248, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(56, 189, 248, 0.03) 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(rgba(56, 189, 248, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(56, 189, 248, 0.02) 1px, transparent 1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Buttons
|
||||
============================================ */
|
||||
.btn-primary,
|
||||
button.btn-primary,
|
||||
a.btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 24px;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-primary-text);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-medium);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--duration-fast) var(--ease-default);
|
||||
text-decoration: none;
|
||||
box-shadow: var(--shadow-none);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--color-primary-hover);
|
||||
box-shadow: var(--shadow-subtle);
|
||||
}
|
||||
|
||||
.btn-primary:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px var(--color-border-focus);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
background: var(--color-primary-active);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-secondary,
|
||||
button.btn-secondary,
|
||||
a.btn-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 24px;
|
||||
background: transparent;
|
||||
color: var(--color-primary);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-medium);
|
||||
border: 1px solid var(--color-border-default);
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-fast) var(--ease-default);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--color-primary-light);
|
||||
border-color: var(--color-primary-border);
|
||||
}
|
||||
|
||||
.btn-secondary:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px var(--color-border-focus);
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
background: var(--color-primary-light);
|
||||
}
|
||||
|
||||
.btn-secondary:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-tertiary,
|
||||
button.btn-tertiary,
|
||||
a.btn-tertiary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 16px;
|
||||
background: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-normal);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: color var(--duration-fast) var(--ease-default);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-tertiary:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
.btn-tertiary:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px var(--color-border-focus);
|
||||
}
|
||||
|
||||
.btn-tertiary:active {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.btn-tertiary:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Cards
|
||||
============================================ */
|
||||
.card {
|
||||
background: var(--color-bg-secondary);
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-none);
|
||||
transition: border-color var(--duration-normal) var(--ease-default);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: var(--color-border-default);
|
||||
}
|
||||
|
||||
.card:focus-within {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px var(--color-border-focus);
|
||||
}
|
||||
|
||||
.card-active {
|
||||
border-color: var(--color-primary-border);
|
||||
}
|
||||
|
||||
.card-elevated {
|
||||
box-shadow: var(--shadow-subtle);
|
||||
}
|
||||
|
||||
.card-elevated:hover {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Input Fields
|
||||
============================================ */
|
||||
.input,
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="number"],
|
||||
input[type="search"],
|
||||
input[type="url"],
|
||||
textarea,
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
border: 1px solid var(--color-border-secondary);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--duration-fast) var(--ease-default);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.input::placeholder,
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.input:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border-color: var(--color-primary-border);
|
||||
box-shadow: 0 0 0 3px var(--color-primary-light);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.input:disabled,
|
||||
input:disabled,
|
||||
textarea:disabled,
|
||||
select:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Input States */
|
||||
.input-error,
|
||||
input.input-error,
|
||||
textarea.input-error {
|
||||
border-color: var(--color-error);
|
||||
box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
.input-error:focus {
|
||||
box-shadow: 0 0 0 3px var(--color-error-light);
|
||||
}
|
||||
|
||||
.input-success,
|
||||
input.input-success,
|
||||
textarea.input-success {
|
||||
border-color: var(--color-success);
|
||||
box-shadow: 0 0 0 2px var(--color-success-light);
|
||||
}
|
||||
|
||||
.input-success:focus {
|
||||
box-shadow: 0 0 0 3px var(--color-success-light);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Hero Sections
|
||||
============================================ */
|
||||
/* ============================================
|
||||
Hero Section - Minimal
|
||||
============================================ */
|
||||
.hero-section {
|
||||
padding: 0.75rem 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-tight);
|
||||
color: var(--color-text-primary);
|
||||
letter-spacing: -0.01em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hero-title {
|
||||
font-size: var(--text-xl);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-normal);
|
||||
color: var(--color-text-secondary);
|
||||
line-height: var(--leading-normal);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Icon Hover Effects
|
||||
============================================ */
|
||||
.icon-hover {
|
||||
transition: all var(--duration-fast) var(--ease-default);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-hover:hover {
|
||||
transform: scale(1.1);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Status Badges
|
||||
============================================ */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 12px;
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-medium);
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: var(--color-success-light);
|
||||
color: var(--color-success);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: var(--color-warning-light);
|
||||
color: var(--color-warning);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge-error {
|
||||
background: var(--color-error-light);
|
||||
color: var(--color-error);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background: var(--color-info-light);
|
||||
color: var(--color-info);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge-gradient {
|
||||
background: var(--gradient-primary);
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Navigation
|
||||
============================================ */
|
||||
.nav-link {
|
||||
color: var(--color-text-secondary);
|
||||
text-decoration: none;
|
||||
transition: all var(--duration-fast) var(--ease-default);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
.nav-link-active {
|
||||
color: var(--color-primary);
|
||||
background: var(--color-primary-light);
|
||||
}
|
||||
|
||||
.nav-link-active:hover {
|
||||
color: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
P2P/Network Specific Components
|
||||
============================================ */
|
||||
.animation-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 25vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, var(--color-bg-primary) 0%, var(--color-bg-secondary) 100%);
|
||||
}
|
||||
|
||||
.text-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fa-circle-nodes {
|
||||
animation: rotateCircleNodes 8s linear infinite;
|
||||
display: inline-block;
|
||||
filter: drop-shadow(0 0 8px var(--color-primary));
|
||||
}
|
||||
|
||||
.fa-flask {
|
||||
animation: shakeFlask 3s ease-in-out infinite;
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
.active-node {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.active-node::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--color-primary), transparent);
|
||||
animation: nodeGlow 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Responsive Adjustments
|
||||
============================================ */
|
||||
@media (max-width: 640px) {
|
||||
.btn-primary,
|
||||
.btn-secondary,
|
||||
.btn-tertiary {
|
||||
padding: 0.625rem 1.25rem;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.hero-section {
|
||||
padding: 0.5rem 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: var(--font-body, 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif);
|
||||
}
|
||||
.chat-container { height: 90vh; display: flex; flex-direction: column; }
|
||||
.chat-messages { overflow-y: auto; flex-grow: 1; }
|
||||
@@ -79,3 +79,28 @@ li {
|
||||
li:last-child {
|
||||
margin-bottom: 0; /* Removes bottom margin from the last item */
|
||||
}
|
||||
|
||||
/* Scrollbar Styling - Minimal */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-bg-primary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-bg-secondary);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--color-bg-secondary) var(--color-bg-primary);
|
||||
}
|
||||
|
||||
113
core/http/static/theme.css
Normal file
113
core/http/static/theme.css
Normal file
@@ -0,0 +1,113 @@
|
||||
/* LocalAI Theme - CSS Variables System */
|
||||
/* Based on logo color palette: cyan, teal, navy, purple */
|
||||
|
||||
:root {
|
||||
/* Base Colors */
|
||||
--color-bg-primary: #0F172A; /* Deep navy background */
|
||||
--color-bg-secondary: #1E293B; /* Elevated surfaces */
|
||||
--color-bg-tertiary: #1E293B; /* Cards, panels */
|
||||
--color-bg-overlay: rgba(15, 23, 42, 0.8); /* Modals, overlays */
|
||||
|
||||
/* Brand Colors */
|
||||
--color-primary: #38BDF8; /* Cyan - primary actions */
|
||||
--color-primary-hover: #0EA5E9; /* Darker cyan on hover */
|
||||
--color-primary-active: #0284C7; /* Active state */
|
||||
--color-primary-text: #FFFFFF; /* Text on primary background */
|
||||
--color-primary-light: rgba(56, 189, 248, 0.08); /* Light cyan backgrounds (reduced) */
|
||||
--color-primary-border: rgba(56, 189, 248, 0.15); /* Cyan borders (reduced) */
|
||||
|
||||
--color-secondary: #14B8A6; /* Teal - secondary actions */
|
||||
--color-secondary-hover: #0D9488; /* Darker teal on hover */
|
||||
--color-secondary-light: rgba(20, 184, 166, 0.1);
|
||||
|
||||
--color-accent: #8B5CF6; /* Purple - special states */
|
||||
--color-accent-hover: #7C3AED; /* Darker purple on hover */
|
||||
--color-accent-light: rgba(139, 92, 246, 0.1);
|
||||
|
||||
--color-accent-purple: #A78BFA; /* Light purple for gradients */
|
||||
--color-accent-teal: #2DD4BF; /* Light teal for gradients */
|
||||
|
||||
/* Text Colors */
|
||||
--color-text-primary: #E5E7EB; /* Primary text */
|
||||
--color-text-secondary: #94A3B8; /* Secondary text */
|
||||
--color-text-muted: #64748B; /* Tertiary text */
|
||||
--color-text-disabled: #475569; /* Disabled text */
|
||||
--color-text-inverse: #0F172A; /* Text on light backgrounds */
|
||||
|
||||
/* Border Colors - Minimal System */
|
||||
--color-border-subtle: rgba(148, 163, 184, 0.08); /* Minimal borders */
|
||||
--color-border-default: rgba(148, 163, 184, 0.12); /* Default borders */
|
||||
--color-border-strong: rgba(56, 189, 248, 0.2); /* Focus borders */
|
||||
--color-border-divider: rgba(148, 163, 184, 0.06); /* Section dividers */
|
||||
--color-border-primary: rgba(56, 189, 248, 0.15); /* Primary borders (reduced opacity) */
|
||||
--color-border-secondary: rgba(148, 163, 184, 0.1);
|
||||
--color-border-focus: rgba(56, 189, 248, 0.3); /* Focus borders (reduced) */
|
||||
|
||||
/* Status Colors */
|
||||
--color-success: #14B8A6; /* Use teal for success (aligned with logo) */
|
||||
--color-success-light: rgba(20, 184, 166, 0.1);
|
||||
--color-warning: #F59E0B;
|
||||
--color-warning-light: rgba(245, 158, 11, 0.1);
|
||||
--color-error: #EF4444;
|
||||
--color-error-light: rgba(239, 68, 68, 0.1);
|
||||
--color-info: #38BDF8; /* Use cyan for info */
|
||||
--color-info-light: rgba(56, 189, 248, 0.1);
|
||||
|
||||
/* Gradient Definitions */
|
||||
--gradient-primary: linear-gradient(135deg, #38BDF8 0%, #8B5CF6 50%, #14B8A6 100%);
|
||||
--gradient-hero: linear-gradient(135deg, #0F172A 0%, #1E293B 50%, #0F172A 100%);
|
||||
--gradient-card: linear-gradient(135deg, rgba(56, 189, 248, 0.05) 0%, rgba(139, 92, 246, 0.05) 100%);
|
||||
--gradient-text: linear-gradient(135deg, #38BDF8 0%, #8B5CF6 50%, #14B8A6 100%);
|
||||
|
||||
/* Shadows - Minimal System */
|
||||
--shadow-none: none;
|
||||
--shadow-subtle: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
|
||||
--shadow-glow: 0 0 0 1px rgba(56, 189, 248, 0.1), 0 0 8px rgba(56, 189, 248, 0.15); /* Minimal glow */
|
||||
|
||||
/* Animation Timing - Minimal */
|
||||
--duration-instant: 100ms;
|
||||
--duration-fast: 150ms;
|
||||
--duration-normal: 200ms;
|
||||
--duration-slow: 300ms;
|
||||
|
||||
/* Animation Easing */
|
||||
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--ease-spring: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
|
||||
/* Spacing Scale (for reference, used via Tailwind) */
|
||||
--spacing-xs: 0.25rem; /* 4px */
|
||||
--spacing-sm: 0.5rem; /* 8px */
|
||||
--spacing-md: 1rem; /* 16px */
|
||||
--spacing-lg: 1.5rem; /* 24px */
|
||||
--spacing-xl: 2rem; /* 32px */
|
||||
--spacing-2xl: 3rem; /* 48px */
|
||||
--spacing-3xl: 4rem; /* 64px */
|
||||
|
||||
/* Border Radius */
|
||||
--radius-none: 0;
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 6px; /* Updated per PRD */
|
||||
--radius-lg: 8px;
|
||||
--radius-xl: 12px;
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* Width System - Container Sizes */
|
||||
--width-xs: 20rem; /* 320px */
|
||||
--width-sm: 24rem; /* 384px */
|
||||
--width-md: 28rem; /* 448px */
|
||||
--width-lg: 32rem; /* 512px */
|
||||
--width-xl: 36rem; /* 576px */
|
||||
--width-2xl: 42rem; /* 672px */
|
||||
--width-3xl: 48rem; /* 768px */
|
||||
--width-4xl: 56rem; /* 896px */
|
||||
--width-5xl: 64rem; /* 1024px */
|
||||
--width-6xl: 72rem; /* 1152px */
|
||||
--width-7xl: 80rem; /* 1280px */
|
||||
}
|
||||
|
||||
195
core/http/static/typography.css
Normal file
195
core/http/static/typography.css
Normal file
@@ -0,0 +1,195 @@
|
||||
/* LocalAI Typography System */
|
||||
/* Font-face declarations and typography variables */
|
||||
|
||||
/* Playfair Display - Display/Headline Font */
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
src: url('/static/assets/playfair-display-regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
src: url('/static/assets/playfair-display-semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
src: url('/static/assets/playfair-display-bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Space Grotesk - Body Font */
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
src: url('/static/assets/space-grotesk-regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
src: url('/static/assets/space-grotesk-medium.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
src: url('/static/assets/space-grotesk-semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
src: url('/static/assets/space-grotesk-bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* JetBrains Mono - Monospace Font */
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('/static/assets/jetbrains-mono-regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('/static/assets/jetbrains-mono-medium.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('/static/assets/jetbrains-mono-semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* Font Families */
|
||||
--font-display: 'Playfair Display', serif;
|
||||
--font-body: 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
|
||||
/* Font Sizes */
|
||||
--text-xs: 0.75rem; /* 12px */
|
||||
--text-sm: 0.875rem; /* 14px */
|
||||
--text-base: 1rem; /* 16px */
|
||||
--text-lg: 1.125rem; /* 18px */
|
||||
--text-xl: 1.25rem; /* 20px */
|
||||
--text-2xl: 1.5rem; /* 24px */
|
||||
--text-3xl: 1.875rem; /* 30px */
|
||||
--text-4xl: 2.25rem; /* 36px */
|
||||
--text-5xl: 3rem; /* 48px */
|
||||
--text-6xl: 3.75rem; /* 60px */
|
||||
--text-7xl: 4.5rem; /* 72px */
|
||||
|
||||
/* Line Heights */
|
||||
--leading-tight: 1.25;
|
||||
--leading-snug: 1.375;
|
||||
--leading-normal: 1.5;
|
||||
--leading-relaxed: 1.625;
|
||||
--leading-loose: 2;
|
||||
|
||||
/* Font Weights */
|
||||
--weight-light: 300;
|
||||
--weight-normal: 400;
|
||||
--weight-medium: 500;
|
||||
--weight-semibold: 600;
|
||||
--weight-bold: 700;
|
||||
--weight-extrabold: 800;
|
||||
}
|
||||
|
||||
/* Base typography */
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-normal);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
h1, .h1 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: var(--weight-bold);
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
h2, .h2 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
h3, .h3 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-snug);
|
||||
}
|
||||
|
||||
h4, .h4 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
h5, .h5 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: var(--weight-medium);
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
h6, .h6 {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-medium);
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
/* Code and monospace */
|
||||
code, pre, kbd, samp {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* Responsive typography adjustments */
|
||||
@media (max-width: 640px) {
|
||||
h1, .h1 {
|
||||
font-size: var(--text-3xl);
|
||||
}
|
||||
|
||||
h2, .h2 {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
|
||||
h3, .h3 {
|
||||
font-size: var(--text-xl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
<div class="mb-6 text-6xl text-[#38BDF8]">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
404 - Page Not Found
|
||||
</span>
|
||||
<h1 class="hero-title mb-4">
|
||||
404 - Page Not Found
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8] mb-6">The page you're looking for doesn't exist or has been moved</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
|
||||
<div class="container mx-auto px-4 py-8 flex-grow max-w-6xl">
|
||||
<!-- Header -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="hero-section">
|
||||
<div class="hero-content flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold text-[#E5E7EB] mb-2">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] via-[#8B5CF6] to-[#38BDF8]">
|
||||
Job Details
|
||||
</span>
|
||||
<h1 class="hero-title">
|
||||
Job Details
|
||||
</h1>
|
||||
<p class="text-lg text-[#94A3B8]">Live job status, reasoning traces, and execution details</p>
|
||||
<p class="hero-subtitle">Live job status, reasoning traces, and execution details</p>
|
||||
</div>
|
||||
<a href="/agent-jobs" class="text-[#94A3B8] hover:text-[#E5E7EB]">
|
||||
<i class="fas fa-arrow-left mr-2"></i>Back to Jobs
|
||||
@@ -26,7 +24,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Job Status Card -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8">
|
||||
<div class="card p-8 mb-8">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB]">Job Status</h2>
|
||||
<div class="flex items-center space-x-4">
|
||||
@@ -41,7 +39,8 @@
|
||||
x-text="job.status ? job.status.toUpperCase() : 'LOADING...'"></span>
|
||||
<button x-show="job.status === 'pending' || job.status === 'running'"
|
||||
@click="cancelJob()"
|
||||
class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
class="btn-primary"
|
||||
style="background: var(--color-error);">
|
||||
<i class="fas fa-stop mr-2"></i>Cancel
|
||||
</button>
|
||||
</div>
|
||||
@@ -76,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Agent Prompt Template -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8" x-show="task && task.prompt">
|
||||
<div class="card p-8 mb-8" x-show="task && task.prompt">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] mb-6">Agent Prompt Template</h2>
|
||||
<p class="text-sm text-[#94A3B8] mb-4">The original prompt template from the task definition.</p>
|
||||
<div class="bg-[#101827] p-4 rounded text-[#E5E7EB] whitespace-pre-wrap font-mono text-sm" x-text="task.prompt"></div>
|
||||
@@ -97,7 +96,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Rendered Job Prompt -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8" x-show="task && task.prompt">
|
||||
<div class="card p-8 mb-8" x-show="task && task.prompt">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] mb-6">Rendered Job Prompt</h2>
|
||||
<p class="text-sm text-[#94A3B8] mb-4">The prompt with parameters substituted, as it was sent to the agent.</p>
|
||||
<div class="bg-[#101827] p-4 rounded text-[#E5E7EB] whitespace-pre-wrap" x-text="getRenderedPrompt()"></div>
|
||||
@@ -110,7 +109,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div class="bg-[#1E293B] border border-red-500/20 rounded-xl p-8 mb-8" x-show="job.error">
|
||||
<div class="card p-8 mb-8" x-show="job.error" style="border-color: var(--color-error);">
|
||||
<h2 class="text-2xl font-semibold text-red-400 mb-6">Error</h2>
|
||||
<div class="bg-red-900/20 p-4 rounded text-red-400 whitespace-pre-wrap" x-text="job.error"></div>
|
||||
</div>
|
||||
|
||||
@@ -2,101 +2,97 @@
|
||||
<html lang="en">
|
||||
{{template "views/partials/head" .}}
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen" x-data="agentJobs()" x-init="init()">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
<!-- Header -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="hero-section">
|
||||
<div class="hero-content flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold text-[#E5E7EB] mb-2">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] via-[#8B5CF6] to-[#38BDF8]">
|
||||
Agent Jobs
|
||||
</span>
|
||||
<h1 class="hero-title">
|
||||
Agent Jobs
|
||||
</h1>
|
||||
<p class="text-lg text-[#94A3B8]">Manage agent tasks and monitor job execution</p>
|
||||
<p class="hero-subtitle">Manage agent tasks and monitor job execution</p>
|
||||
</div>
|
||||
<a href="/agent-jobs/tasks/new" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg transition-colors" x-show="hasMCPModels">
|
||||
<a href="/agent-jobs/tasks/new" class="bg-[var(--color-primary)] hover:bg-[var(--color-primary-hover)] text-white px-6 py-3 rounded-lg transition-colors" x-show="hasMCPModels">
|
||||
<i class="fas fa-plus mr-2"></i>Create Task
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wizard: No Models -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-12 mb-8" x-show="!hasModels">
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-accent-border)]/20 rounded-xl p-12 mb-8" x-show="!hasModels">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-[#8B5CF6]/10 border border-[#8B5CF6]/20 mb-6">
|
||||
<i class="text-[#8B5CF6] text-2xl fas fa-robot"></i>
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-[var(--color-accent)]/10 border border-[var(--color-accent-border)]/20 mb-6">
|
||||
<i class="text-[var(--color-accent)] text-2xl fas fa-robot"></i>
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
No Models Installed
|
||||
</span>
|
||||
<h2 class="h2 mb-4">
|
||||
No Models Installed
|
||||
</h2>
|
||||
<p class="text-xl text-[#94A3B8] mb-8">
|
||||
<p class="text-xl text-[var(--color-text-secondary)] mb-8">
|
||||
To use Agent Jobs, you need to install a model first. Agent Jobs require models with MCP (Model Context Protocol) configuration.
|
||||
</p>
|
||||
|
||||
<!-- Features Preview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-10">
|
||||
<div class="bg-[#101827] border border-[#38BDF8]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-images text-[#38BDF8] text-xl"></i>
|
||||
<div class="bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-[var(--color-primary-light)] rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-images text-[var(--color-primary)] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Model Gallery</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Browse and install pre-configured models</p>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">Model Gallery</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Browse and install pre-configured models</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-purple-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-upload text-[#8B5CF6] text-xl"></i>
|
||||
<div class="bg-[var(--color-bg-primary)] border border-[var(--color-accent-border)]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-[var(--color-accent-light)] rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-upload text-[var(--color-accent)] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Import Models</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Upload your own model files</p>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">Import Models</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Upload your own model files</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-green-500/20 rounded-lg p-4">
|
||||
<div class="bg-[var(--color-bg-primary)] border border-green-500/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-green-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-code text-green-400 text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">API Download</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Use the API to download models programmatically</p>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">API Download</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Use the API to download models programmatically</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Setup Instructions -->
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-rocket text-[#8B5CF6] mr-2"></i>
|
||||
<div class="bg-[var(--color-bg-primary)] border border-[var(--color-accent-border)]/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-rocket text-[var(--color-accent)] mr-2"></i>
|
||||
How to Get Started
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">1</span>
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent)]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">1</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Browse the Model Gallery</p>
|
||||
<p class="text-[#94A3B8] text-sm">Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Browse the Model Gallery</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">2</span>
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent)]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">2</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Install a Model</p>
|
||||
<p class="text-[#94A3B8] text-sm">Click on a model from the gallery to install it, or use the import feature to upload your own model files.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Install a Model</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Click on a model from the gallery to install it, or use the import feature to upload your own model files.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">3</span>
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent)]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">3</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Configure MCP</p>
|
||||
<p class="text-[#94A3B8] text-sm">After installing a model, configure MCP (Model Context Protocol) to enable Agent Jobs functionality.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Configure MCP</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">After installing a model, configure MCP (Model Context Protocol) to enable Agent Jobs functionality.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,17 +100,17 @@
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/browse/"
|
||||
class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
class="inline-flex items-center bg-[var(--color-accent)] hover:bg-[var(--color-accent)]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-images mr-2"></i>
|
||||
Browse Model Gallery
|
||||
</a>
|
||||
<a href="/import-model"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
class="inline-flex items-center bg-[var(--color-primary)] hover:bg-[var(--color-primary)]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
Import Model
|
||||
</a>
|
||||
<a href="https://localai.io/basics/getting_started/" target="_blank"
|
||||
class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#8B5CF6]/20 text-[#E5E7EB] py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
class="inline-flex items-center bg-[var(--color-bg-secondary)] hover:bg-[var(--color-bg-secondary)]/80 border border-[var(--color-accent-border)]/20 text-[var(--color-text-primary)] py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-graduation-cap mr-2"></i>
|
||||
Getting Started
|
||||
<i class="fas fa-external-link-alt ml-2 text-sm"></i>
|
||||
@@ -124,32 +120,30 @@
|
||||
</div>
|
||||
|
||||
<!-- Wizard: Models but No MCP -->
|
||||
<div class="bg-[#1E293B] border border-yellow-500/20 rounded-xl p-12 mb-8" x-show="hasModels && !hasMCPModels">
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-yellow-500/20 rounded-xl p-12 mb-8" x-show="hasModels && !hasMCPModels">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-yellow-500/10 border border-yellow-500/20 mb-6">
|
||||
<i class="text-yellow-500 text-2xl fas fa-exclamation-triangle"></i>
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-yellow-500">
|
||||
MCP Configuration Required
|
||||
</span>
|
||||
<h2 class="h2 mb-4">
|
||||
MCP Configuration Required
|
||||
</h2>
|
||||
<p class="text-xl text-[#94A3B8] mb-8">
|
||||
<p class="text-xl text-[var(--color-text-secondary)] mb-8">
|
||||
You have models installed, but none have MCP (Model Context Protocol) enabled. Agent Jobs require MCP to function.
|
||||
</p>
|
||||
|
||||
<!-- Available Models List -->
|
||||
<div class="bg-[#101827] border border-yellow-500/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<div class="bg-[var(--color-bg-primary)] border border-yellow-500/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-list text-yellow-500 mr-2"></i>
|
||||
Available Models
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
<template x-for="model in availableModels" :key="model.name">
|
||||
<div class="flex items-center justify-between p-3 bg-[#0A0E1A] rounded-lg border border-[#38BDF8]/10">
|
||||
<div class="flex items-center justify-between p-3 bg-[#0A0E1A] rounded-lg border border-[var(--color-primary-border)]/10">
|
||||
<div class="flex items-center space-x-3">
|
||||
<i class="fas fa-cube text-[#38BDF8]"></i>
|
||||
<span class="text-[#E5E7EB] font-medium" x-text="model.name"></span>
|
||||
<i class="fas fa-cube text-[var(--color-primary)]"></i>
|
||||
<span class="text-[var(--color-text-primary)] font-medium" x-text="model.name"></span>
|
||||
</div>
|
||||
<a :href="'/models/edit/' + model.name"
|
||||
class="inline-flex items-center bg-yellow-600 hover:bg-yellow-700 text-white px-4 py-2 rounded-lg transition-colors text-sm">
|
||||
@@ -162,8 +156,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Setup Instructions -->
|
||||
<div class="bg-[#101827] border border-yellow-500/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<div class="bg-[var(--color-bg-primary)] border border-yellow-500/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-cog text-yellow-500 mr-2"></i>
|
||||
How to Enable MCP
|
||||
</h3>
|
||||
@@ -173,8 +167,8 @@
|
||||
<span class="text-yellow-500 font-bold text-sm">1</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Edit a Model Configuration</p>
|
||||
<p class="text-[#94A3B8] text-sm">Click "Configure MCP" on any model above, or navigate to the model editor to add MCP configuration.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Edit a Model Configuration</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Click "Configure MCP" on any model above, or navigate to the model editor to add MCP configuration.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
@@ -182,8 +176,8 @@
|
||||
<span class="text-yellow-500 font-bold text-sm">2</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Add MCP Configuration</p>
|
||||
<p class="text-[#94A3B8] text-sm">In the model YAML, add MCP server or stdio configuration. See the documentation for detailed examples.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Add MCP Configuration</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">In the model YAML, add MCP server or stdio configuration. See the documentation for detailed examples.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
@@ -191,8 +185,8 @@
|
||||
<span class="text-yellow-500 font-bold text-sm">3</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Save and Return</p>
|
||||
<p class="text-[#94A3B8] text-sm">After saving the MCP configuration, return to this page to create your first Agent Job task.</p>
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Save and Return</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">After saving the MCP configuration, return to this page to create your first Agent Job task.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,7 +200,7 @@
|
||||
<i class="fas fa-external-link-alt ml-2 text-sm"></i>
|
||||
</a>
|
||||
<a href="/manage"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
class="inline-flex items-center bg-[var(--color-primary)] hover:bg-[var(--color-primary)]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-cog mr-2"></i>
|
||||
Manage Models
|
||||
</a>
|
||||
@@ -215,32 +209,32 @@
|
||||
</div>
|
||||
|
||||
<!-- Tasks Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8" x-show="hasMCPModels">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] mb-6">Tasks</h2>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded-xl p-8 mb-8" x-show="hasMCPModels">
|
||||
<h2 class="text-2xl font-semibold text-[var(--color-text-primary)] mb-6">Tasks</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b border-[#38BDF8]/20">
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Name</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Model</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Cron</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Status</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Actions</th>
|
||||
<tr class="border-b border-[var(--color-primary-border)]/20">
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Name</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Model</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Cron</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Status</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="task in tasks" :key="task.id">
|
||||
<tr class="border-b border-[#38BDF8]/10 hover:bg-[#101827]">
|
||||
<tr class="border-b border-[var(--color-primary-border)]/10 hover:bg-[var(--color-bg-primary)]">
|
||||
<td class="py-3 px-4">
|
||||
<a :href="'/agent-jobs/tasks/' + task.id"
|
||||
class="font-semibold text-[#38BDF8] hover:text-[#38BDF8]/80 hover:underline"
|
||||
class="font-semibold text-[var(--color-primary)] hover:text-[var(--color-primary)]/80 hover:underline"
|
||||
x-text="task.name"></a>
|
||||
<div class="text-sm text-[#94A3B8]" x-text="task.description || 'No description'"></div>
|
||||
<div class="text-sm text-[var(--color-text-secondary)]" x-text="task.description || 'No description'"></div>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<a :href="'/chat/' + task.model + '?mcp=true'"
|
||||
class="text-[#38BDF8] hover:text-[#38BDF8]/80 hover:underline"
|
||||
class="text-[var(--color-primary)] hover:text-[var(--color-primary)]/80 hover:underline"
|
||||
x-text="task.model"></a>
|
||||
<a :href="'/models/edit/' + task.model"
|
||||
class="text-yellow-400 hover:text-yellow-300"
|
||||
@@ -250,8 +244,8 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<span x-show="task.cron" class="text-[#38BDF8]" x-text="task.cron"></span>
|
||||
<span x-show="!task.cron" class="text-[#94A3B8]">-</span>
|
||||
<span x-show="task.cron" class="text-[var(--color-primary)]" x-text="task.cron"></span>
|
||||
<span x-show="!task.cron" class="text-[var(--color-text-secondary)]">-</span>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<span :class="task.enabled ? 'bg-green-500' : 'bg-gray-500'"
|
||||
@@ -280,7 +274,7 @@
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-show="tasks.length === 0">
|
||||
<td colspan="5" class="py-8 text-center text-[#94A3B8]">
|
||||
<td colspan="5" class="py-8 text-center text-[var(--color-text-secondary)]">
|
||||
No tasks found. <a href="/agent-jobs/tasks/new" class="text-blue-400 hover:text-blue-300">Create one</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -290,12 +284,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Jobs Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8" x-show="hasMCPModels">
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded-xl p-8" x-show="hasMCPModels">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB]">Job History</h2>
|
||||
<h2 class="text-2xl font-semibold text-[var(--color-text-primary)]">Job History</h2>
|
||||
<div class="flex space-x-4">
|
||||
<select x-model="jobFilter" @change="fetchJobs()"
|
||||
class="bg-[#101827] border border-[#38BDF8]/20 rounded px-4 py-2 text-[#E5E7EB]">
|
||||
class="bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded px-4 py-2 text-[var(--color-text-primary)]">
|
||||
<option value="">All Status</option>
|
||||
<option value="pending">Pending</option>
|
||||
<option value="running">Running</option>
|
||||
@@ -313,26 +307,26 @@
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b border-[#38BDF8]/20">
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Job ID</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Task</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Status</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Created</th>
|
||||
<th class="text-left py-3 px-4 text-[#94A3B8]">Actions</th>
|
||||
<tr class="border-b border-[var(--color-primary-border)]/20">
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Job ID</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Task</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Status</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Created</th>
|
||||
<th class="text-left py-3 px-4 text-[var(--color-text-secondary)]">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="job in jobs" :key="job.id">
|
||||
<tr class="border-b border-[#38BDF8]/10 hover:bg-[#101827]">
|
||||
<tr class="border-b border-[var(--color-primary-border)]/10 hover:bg-[var(--color-bg-primary)]">
|
||||
<td class="py-3 px-4">
|
||||
<a :href="'/agent-jobs/jobs/' + job.id"
|
||||
class="font-mono text-sm text-[#38BDF8] hover:text-[#38BDF8]/80 hover:underline"
|
||||
class="font-mono text-sm text-[var(--color-primary)] hover:text-[var(--color-primary)]/80 hover:underline"
|
||||
x-text="job.id.substring(0, 8) + '...'"
|
||||
:title="job.id"></a>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<a :href="'/agent-jobs/tasks/' + job.task_id"
|
||||
class="text-[#38BDF8] hover:text-[#38BDF8]/80 hover:underline"
|
||||
class="text-[var(--color-primary)] hover:text-[var(--color-primary)]/80 hover:underline"
|
||||
x-text="getTaskName(job.task_id)"
|
||||
:title="'Task ID: ' + job.task_id"></a>
|
||||
</td>
|
||||
@@ -347,7 +341,7 @@
|
||||
class="px-2 py-1 rounded text-xs text-white"
|
||||
x-text="job.status"></span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-[#94A3B8] text-sm" x-text="formatDate(job.created_at)"></td>
|
||||
<td class="py-3 px-4 text-[var(--color-text-secondary)] text-sm" x-text="formatDate(job.created_at)"></td>
|
||||
<td class="py-3 px-4">
|
||||
<button x-show="job.status === 'pending' || job.status === 'running'"
|
||||
@click="cancelJob(job.id)"
|
||||
@@ -358,7 +352,7 @@
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-show="jobs.length === 0">
|
||||
<td colspan="5" class="py-8 text-center text-[#94A3B8]">No jobs found</td>
|
||||
<td colspan="5" class="py-8 text-center text-[var(--color-text-secondary)]">No jobs found</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -371,41 +365,41 @@
|
||||
x-cloak
|
||||
@click.away="showExecuteTaskModal = false; selectedTaskForExecution = null; executionParameters = {}; executionParametersText = ''"
|
||||
class="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 max-w-2xl w-full mx-4">
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded-xl p-8 max-w-2xl w-full mx-4">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h3 class="text-2xl font-semibold text-[#E5E7EB]">Execute Task</h3>
|
||||
<h3 class="text-2xl font-semibold text-[var(--color-text-primary)]">Execute Task</h3>
|
||||
<button @click="showExecuteTaskModal = false; selectedTaskForExecution = null; executionParameters = {}; executionParametersText = ''"
|
||||
class="text-[#94A3B8] hover:text-[#E5E7EB]">
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]">
|
||||
<i class="fas fa-times text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
<template x-if="selectedTaskForExecution">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Task</label>
|
||||
<div class="text-[#94A3B8]" x-text="selectedTaskForExecution.name"></div>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Task</label>
|
||||
<div class="text-[var(--color-text-secondary)]" x-text="selectedTaskForExecution.name"></div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Parameters</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-3">
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Parameters</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-3">
|
||||
Enter parameters as key-value pairs (one per line, format: key=value).
|
||||
These will be used to template the prompt.
|
||||
</p>
|
||||
<textarea x-model="executionParametersText"
|
||||
rows="6"
|
||||
placeholder="user_name=Alice job_title=Software Engineer task_description=Review code changes"
|
||||
class="w-full bg-[#101827] border border-[#38BDF8]/20 rounded px-4 py-2 text-[#E5E7EB] font-mono text-sm focus:border-[#38BDF8] focus:ring-2 focus:ring-[#38BDF8]/50"></textarea>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">
|
||||
Example: <code class="bg-[#101827] px-1 py-0.5 rounded text-[#38BDF8]">user_name=Alice</code>
|
||||
class="w-full bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded px-4 py-2 text-[var(--color-text-primary)] font-mono text-sm focus:border-[var(--color-primary-border)] focus:ring-2 focus:ring-[#38BDF8]/50"></textarea>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">
|
||||
Example: <code class="bg-[var(--color-bg-primary)] px-1 py-0.5 rounded text-[var(--color-primary)]">user_name=Alice</code>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-4">
|
||||
<button @click="showExecuteTaskModal = false; selectedTaskForExecution = null; executionParameters = {}; executionParametersText = ''"
|
||||
class="px-4 py-2 bg-[#101827] hover:bg-[#0A0E1A] text-[#E5E7EB] rounded-lg transition-colors">
|
||||
class="px-4 py-2 bg-[var(--color-bg-primary)] hover:bg-[#0A0E1A] text-[var(--color-text-primary)] rounded-lg transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button @click="executeTaskWithParameters()"
|
||||
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">
|
||||
class="px-4 py-2 bg-[var(--color-primary)] hover:bg-[var(--color-primary-hover)] text-white rounded-lg transition-colors">
|
||||
<i class="fas fa-play mr-2"></i>Execute
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold text-[#E5E7EB] mb-2">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] via-[#8B5CF6] to-[#38BDF8]">
|
||||
<span x-text="isNewTask ? 'Create Task' : (isEditMode ? 'Edit Task' : 'Task Details')"></span>
|
||||
</span>
|
||||
<h1 class="hero-title">
|
||||
<span x-text="isNewTask ? 'Create Task' : (isEditMode ? 'Edit Task' : 'Task Details')"></span>
|
||||
</h1>
|
||||
<p class="text-lg text-[#94A3B8]" x-text="isNewTask ? 'Create a new agent task' : (task ? task.name : 'Loading...')"></p>
|
||||
</div>
|
||||
|
||||
@@ -35,14 +35,12 @@
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
|
||||
<!-- Hero Header -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8 mb-12">
|
||||
<div class="max-w-5xl mx-auto text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#8B5CF6] via-[#38BDF8] to-[#8B5CF6]">
|
||||
Backend Management
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
Backend Management
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-[#94A3B8] mb-6 font-light">
|
||||
<p class="hero-subtitle">
|
||||
Discover and install AI backends to power your models
|
||||
</p>
|
||||
<div class="flex flex-wrap justify-center items-center gap-6 text-sm md:text-base">
|
||||
@@ -56,8 +54,7 @@
|
||||
<span class="font-semibold text-cyan-300" x-text="installedBackends"></span>
|
||||
<span class="text-[#94A3B8] ml-1">installed</span>
|
||||
</a>
|
||||
<a href="https://localai.io/backends/" target="_blank"
|
||||
class="inline-flex items-center bg-cyan-600 hover:bg-cyan-700 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
<a href="https://localai.io/backends/" target="_blank" class="btn-primary">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
<span>Documentation</span>
|
||||
<i class="fas fa-external-link-alt ml-2 text-xs"></i>
|
||||
@@ -69,7 +66,7 @@
|
||||
{{template "views/partials/inprogress" .}}
|
||||
|
||||
<!-- Search and Filter Section -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8 mb-8">
|
||||
<div class="card p-8 mb-8">
|
||||
<div>
|
||||
<!-- Search Input -->
|
||||
<div class="mb-8">
|
||||
@@ -84,7 +81,7 @@
|
||||
<input
|
||||
x-model="searchTerm"
|
||||
@input.debounce.500ms="fetchBackends()"
|
||||
class="w-full pl-12 pr-16 py-4 text-base font-normal text-[#E5E7EB] bg-[#101827] border border-[#1E293B] rounded-lg transition-colors focus:text-[#E5E7EB] focus:bg-[#101827] focus:border-[#8B5CF6] focus:ring-2 focus:ring-[#8B5CF6]/50 focus:outline-none"
|
||||
class="input w-full pl-12 pr-16 py-4"
|
||||
type="search"
|
||||
placeholder="Search backends by name, description or type...">
|
||||
<span class="absolute right-4 top-4" x-show="loading">
|
||||
|
||||
@@ -526,30 +526,30 @@ SOFTWARE.
|
||||
<script defer src="static/chat.js"></script>
|
||||
{{ $allGalleryConfigs:=.GalleryConfig }}
|
||||
{{ $model:=.Model}}
|
||||
<body class="bg-[#101827] text-[#E5E7EB] flex flex-col h-screen" x-data="{ sidebarOpen: true, showClearAlert: false }">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] flex flex-col h-screen" x-data="{ sidebarOpen: true, showClearAlert: false }">
|
||||
{{template "views/partials/navbar" .}}
|
||||
|
||||
<!-- Main container with sidebar toggle -->
|
||||
<div class="flex flex-1 overflow-hidden relative">
|
||||
<!-- Sidebar -->
|
||||
<div
|
||||
class="sidebar bg-[#1E293B] fixed top-14 bottom-0 left-0 w-56 transform transition-transform duration-300 ease-in-out z-30 border-r border-[#101827] overflow-y-auto"
|
||||
class="sidebar bg-[var(--color-bg-secondary)] fixed top-14 bottom-0 left-0 w-56 transform transition-transform duration-300 ease-in-out z-30 border-r border-[var(--color-bg-primary)] overflow-y-auto"
|
||||
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'">
|
||||
|
||||
<div class="p-3 flex justify-between items-center border-b border-[#101827]">
|
||||
<div class="p-3 flex justify-between items-center border-b border-[var(--color-bg-primary)]">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-sm font-semibold text-[#E5E7EB]">Settings</h2>
|
||||
<h2 class="text-sm font-semibold text-[var(--color-text-primary)]">Settings</h2>
|
||||
<a
|
||||
href="https://localai.io/features/text-generation/"
|
||||
target="_blank"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-xs"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-xs"
|
||||
title="Documentation">
|
||||
<i class="fas fa-book"></i>
|
||||
</a>
|
||||
</div>
|
||||
<button
|
||||
@click="sidebarOpen = false"
|
||||
class="text-[#94A3B8] hover:text-[#E5E7EB] focus:outline-none text-xs"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] focus:outline-none text-xs"
|
||||
title="Hide sidebar">
|
||||
<i class="fa-solid fa-chevron-left"></i>
|
||||
</button>
|
||||
@@ -560,14 +560,14 @@ SOFTWARE.
|
||||
<!-- Model selection - Compact -->
|
||||
<div class="space-y-1.5">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="text-xs font-medium text-[#94A3B8] uppercase tracking-wide">Model</label>
|
||||
<label class="text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide">Model</label>
|
||||
{{ if $model }}
|
||||
{{ $galleryConfig:= index $allGalleryConfigs $model}}
|
||||
{{ if $galleryConfig }}
|
||||
<button
|
||||
data-twe-ripple-init
|
||||
data-twe-ripple-color="light"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-xs p-1"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-xs p-1"
|
||||
data-modal-target="model-info-modal"
|
||||
data-modal-toggle="model-info-modal"
|
||||
title="Model Information">
|
||||
@@ -577,7 +577,7 @@ SOFTWARE.
|
||||
{{ end }}
|
||||
{{ if $model }}
|
||||
<a href="/models/edit/{{$model}}"
|
||||
class="text-[#94A3B8] hover:text-yellow-400 transition-colors text-xs p-1"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-warning)] transition-colors text-xs p-1"
|
||||
title="Edit Model Configuration">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
@@ -585,10 +585,10 @@ SOFTWARE.
|
||||
</div>
|
||||
<select
|
||||
id="modelSelector"
|
||||
class="w-full bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#38BDF8] focus:ring-1 focus:ring-[#38BDF8]/50 rounded p-1.5 text-xs appearance-none"
|
||||
class="input w-full p-1.5 text-xs"
|
||||
onchange="updateModelAndContextSize(this);"
|
||||
>
|
||||
<option value="" disabled class="text-[#94A3B8]">Select a model</option>
|
||||
<option value="" disabled class="text-[var(--color-text-secondary)]">Select a model</option>
|
||||
|
||||
{{ range .ModelsConfig }}
|
||||
{{ $cfg := . }}
|
||||
@@ -600,7 +600,7 @@ SOFTWARE.
|
||||
{{ if eq $cfg.Name $model }} selected {{end}}
|
||||
{{ if $cfg.LLMConfig.ContextSize }}data-context-size="{{$cfg.LLMConfig.ContextSize}}"{{ end }}
|
||||
data-has-mcp="{{if $hasMCP}}true{{else}}false{{end}}"
|
||||
class="bg-[#101827] text-[#E5E7EB]"
|
||||
class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]"
|
||||
>
|
||||
{{$cfg.Name}}
|
||||
</option>
|
||||
@@ -611,7 +611,7 @@ SOFTWARE.
|
||||
<option
|
||||
value="chat/{{.}}"
|
||||
{{ if eq . $model }} selected {{ end }}
|
||||
class="bg-[#101827] text-[#E5E7EB]"
|
||||
class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]"
|
||||
>
|
||||
{{.}}
|
||||
</option>
|
||||
@@ -693,17 +693,17 @@ SOFTWARE.
|
||||
}
|
||||
}">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-xs font-semibold text-[#94A3B8] uppercase tracking-wide">Chats</h2>
|
||||
<h2 class="text-xs font-semibold text-[var(--color-text-secondary)] uppercase tracking-wide">Chats</h2>
|
||||
<div class="flex items-center gap-1">
|
||||
<button
|
||||
@click="createNewChat()"
|
||||
class="text-[#38BDF8] hover:text-[#8B5CF6] transition-colors text-xs p-1"
|
||||
class="text-[var(--color-primary)] hover:text-[var(--color-accent)] transition-colors text-xs p-1"
|
||||
title="New Chat">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</button>
|
||||
<button
|
||||
@click="if (confirm('Delete all chats? This cannot be undone.')) { bulkDeleteChats({deleteAll: true}); }"
|
||||
class="text-[#94A3B8] hover:text-red-400 transition-colors text-xs p-1"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-error)] transition-colors text-xs p-1"
|
||||
title="Delete all chats"
|
||||
x-show="$store.chat.chats.length > 0">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
@@ -717,24 +717,24 @@ SOFTWARE.
|
||||
type="text"
|
||||
x-model="searchQuery"
|
||||
placeholder="Search conversations..."
|
||||
class="w-full bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#38BDF8] focus:ring-1 focus:ring-[#38BDF8]/50 rounded px-2 py-1.5 pl-7 text-xs placeholder-[#94A3B8]"
|
||||
class="w-full bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] border border-[var(--color-bg-secondary)] focus:border-[var(--color-primary-border)] focus:ring-1 focus:ring-[var(--color-primary)]/50 rounded px-2 py-1.5 pl-7 text-xs placeholder-[var(--color-text-secondary)]"
|
||||
/>
|
||||
<i class="fa-solid fa-search absolute left-2 top-1/2 transform -translate-y-1/2 text-[#94A3B8] text-xs"></i>
|
||||
<i class="fa-solid fa-search absolute left-2 top-1/2 transform -translate-y-1/2 text-[var(--color-text-secondary)] text-xs"></i>
|
||||
<button
|
||||
x-show="searchQuery.length > 0"
|
||||
@click="searchQuery = ''"
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2 text-[#94A3B8] hover:text-[#E5E7EB] text-xs"
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] text-xs"
|
||||
title="Clear search">
|
||||
<i class="fa-solid fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Chat List -->
|
||||
<div class="max-h-80 overflow-y-auto space-y-1 border border-[#1E293B] rounded p-1.5">
|
||||
<div class="max-h-80 overflow-y-auto space-y-1 border border-[var(--color-bg-secondary)] rounded p-1.5">
|
||||
<template x-for="chat in filteredChats()" :key="chat.id">
|
||||
<div
|
||||
class="flex items-center justify-between p-1.5 rounded hover:bg-[#1E293B] transition-colors cursor-pointer group"
|
||||
:class="{ 'bg-[#38BDF8]/20 border border-[#38BDF8]/40': $store.chat.activeChatId === chat.id }"
|
||||
class="flex items-center justify-between p-1.5 rounded hover:bg-[var(--color-bg-secondary)] transition-colors cursor-pointer group"
|
||||
:class="{ 'bg-[var(--color-primary)]/20 border border-[var(--color-primary-border)]/40': $store.chat.activeChatId === chat.id }"
|
||||
@click="if (editingChatId !== chat.id) switchChat(chat.id)"
|
||||
>
|
||||
<div class="flex-1 min-w-0">
|
||||
@@ -745,7 +745,7 @@ SOFTWARE.
|
||||
@blur="updateChatName(chat.id, editingName); editingChatId = null"
|
||||
@keydown.enter="updateChatName(chat.id, editingName); editingChatId = null"
|
||||
@keydown.escape="editingChatId = null"
|
||||
class="w-full bg-[#101827] text-[#E5E7EB] border border-[#38BDF8] rounded px-1.5 py-0.5 text-xs"
|
||||
class="w-full bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] border border-[var(--color-primary-border)] rounded px-1.5 py-0.5 text-xs"
|
||||
x-ref="editInput"
|
||||
x-effect="if (editingChatId === chat.id) { $refs.editInput?.focus(); editingName = chat.name; }"
|
||||
/>
|
||||
@@ -755,17 +755,17 @@ SOFTWARE.
|
||||
<!-- Loading indicator for active requests -->
|
||||
<div x-show="$store.chat.hasActiveRequest(chat.id)"
|
||||
class="flex-shrink-0">
|
||||
<i class="fa-solid fa-spinner fa-spin text-[#38BDF8] text-[10px]"></i>
|
||||
<i class="fa-solid fa-spinner fa-spin text-[var(--color-primary)] text-[10px]"></i>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div
|
||||
class="text-xs font-medium text-[#E5E7EB] truncate"
|
||||
class="text-xs font-medium text-[var(--color-text-primary)] truncate"
|
||||
@dblclick="editingChatId = chat.id; editingName = chat.name"
|
||||
x-text="chat.name || 'New Chat'"
|
||||
></div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="text-[10px] text-[#94A3B8] truncate" x-text="getLastMessagePreview(chat)"></div>
|
||||
<span class="text-[9px] text-[#94A3B8]/60" x-text="formatChatDate(chat.updatedAt || chat.createdAt)"></span>
|
||||
<div class="text-[10px] text-[var(--color-text-secondary)] truncate" x-text="getLastMessagePreview(chat)"></div>
|
||||
<span class="text-[9px] text-[var(--color-text-secondary)]/60" x-text="formatChatDate(chat.updatedAt || chat.createdAt)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -774,13 +774,13 @@ SOFTWARE.
|
||||
<div class="flex items-center space-x-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button
|
||||
@click.stop="editingChatId = chat.id; editingName = chat.name"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-[10px] p-0.5"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-[10px] p-0.5"
|
||||
title="Rename chat">
|
||||
<i class="fa-solid fa-edit"></i>
|
||||
</button>
|
||||
<button
|
||||
@click.stop="if (confirm('Delete this chat?')) deleteChat(chat.id)"
|
||||
class="text-[#94A3B8] hover:text-red-400 transition-colors text-[10px] p-0.5"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-error)] transition-colors text-[10px] p-0.5"
|
||||
title="Delete chat"
|
||||
x-show="$store.chat.chats.length > 1">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
@@ -788,10 +788,10 @@ SOFTWARE.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div x-show="filteredChats().length === 0 && $store.chat.chats.length > 0" class="text-xs text-[#94A3B8] text-center py-2">
|
||||
<div x-show="filteredChats().length === 0 && $store.chat.chats.length > 0" class="text-xs text-[var(--color-text-secondary)] text-center py-2">
|
||||
No conversations match your search
|
||||
</div>
|
||||
<div x-show="$store.chat.chats.length === 0" class="text-xs text-[#94A3B8] text-center py-2">
|
||||
<div x-show="$store.chat.chats.length === 0" class="text-xs text-[var(--color-text-secondary)] text-center py-2">
|
||||
No chats yet
|
||||
</div>
|
||||
</div>
|
||||
@@ -837,21 +837,21 @@ SOFTWARE.
|
||||
});
|
||||
}
|
||||
}" x-show="mcpAvailable">
|
||||
<div class="flex items-center justify-between px-2 py-1.5 text-xs rounded text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] transition-colors">
|
||||
<span><i class="fa-solid fa-plug mr-1.5 text-[#38BDF8]"></i> MCP Mode</span>
|
||||
<div class="flex items-center justify-between px-2 py-1.5 text-xs rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors">
|
||||
<span><i class="fa-solid fa-plug mr-1.5 text-[var(--color-primary)]"></i> MCP Mode</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" id="mcp-toggle" class="sr-only peer" :checked="$store.chat.activeChat()?.mcpMode || false" @change="if ($store.chat.activeChat()) { $store.chat.activeChat().mcpMode = $event.target.checked; autoSaveChats(); }">
|
||||
<div class="w-9 h-5 bg-[#101827] peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-[#38BDF8]/30 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-[#1E293B] after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-[#38BDF8]"></div>
|
||||
<div class="w-9 h-5 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-[var(--color-primary)]/30 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-[var(--color-bg-secondary)] after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-[var(--color-primary)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- MCP Mode Notification - Compact -->
|
||||
<div x-show="$store.chat.activeChat()?.mcpMode" class="p-2 bg-[#38BDF8]/10 border border-[#38BDF8]/30 rounded text-[#94A3B8] text-[10px]">
|
||||
<div x-show="$store.chat.activeChat()?.mcpMode" class="p-2 bg-[var(--color-primary)]/10 border border-[var(--color-primary-border)]/30 rounded text-[var(--color-text-secondary)] text-[10px]">
|
||||
<div class="flex items-start space-x-1.5">
|
||||
<i class="fa-solid fa-info-circle text-[#38BDF8] mt-0.5"></i>
|
||||
<i class="fa-solid fa-info-circle text-[var(--color-primary)] mt-0.5"></i>
|
||||
<div>
|
||||
<p class="font-medium text-[#E5E7EB] mb-0.5">Non-streaming Mode</p>
|
||||
<p class="text-[#94A3B8]">Full processing before display (may take up to 5 minutes on CPU).</p>
|
||||
<p class="font-medium text-[var(--color-text-primary)] mb-0.5">Non-streaming Mode</p>
|
||||
<p class="text-[var(--color-text-secondary)]">Full processing before display (may take up to 5 minutes on CPU).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -859,9 +859,9 @@ SOFTWARE.
|
||||
|
||||
<button
|
||||
@click="showPromptForm = !showPromptForm"
|
||||
class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] transition-colors"
|
||||
class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"
|
||||
>
|
||||
<span><i class="fa-solid fa-message mr-1.5 text-[#38BDF8]"></i> System Prompt</span>
|
||||
<span><i class="fa-solid fa-message mr-1.5 text-[var(--color-primary)]"></i> System Prompt</span>
|
||||
<i :class="showPromptForm ? 'fa-chevron-up' : 'fa-chevron-down'" class="fa-solid text-[10px]"></i>
|
||||
</button>
|
||||
|
||||
@@ -881,13 +881,14 @@ SOFTWARE.
|
||||
setTimeout(() => {this.showToast = false;}, 2000);
|
||||
}
|
||||
}
|
||||
}" class="p-2 bg-[#1E293B] border border-[#38BDF8]/20 rounded pl-4 border-l-2 border-[#1E293B]">
|
||||
}" class="p-2 bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded pl-4 border-l-2 border-[var(--color-bg-secondary)]">
|
||||
<form id="system_prompt" @submit.prevent="isUpdated" class="flex flex-col space-y-1.5">
|
||||
<textarea
|
||||
type="text"
|
||||
id="systemPrompt"
|
||||
class="input"
|
||||
name="systemPrompt"
|
||||
class="bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#38BDF8] focus:ring-1 focus:ring-[#38BDF8] focus:ring-opacity-50 rounded p-1.5 text-xs appearance-none min-h-20 placeholder-[#94A3B8]"
|
||||
class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] border border-[var(--color-bg-secondary)] focus:border-[var(--color-primary-border)] focus:ring-1 focus:ring-[var(--color-primary)] focus:ring-opacity-50 rounded p-1.5 text-xs appearance-none min-h-20 placeholder-[var(--color-text-secondary)]"
|
||||
placeholder="System prompt"
|
||||
:value="$store.chat.activeChat()?.systemPrompt || ''"
|
||||
@input="if ($store.chat.activeChat()) { $store.chat.activeChat().systemPrompt = $event.target.value; $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
@@ -896,13 +897,13 @@ SOFTWARE.
|
||||
<div
|
||||
x-show="showToast"
|
||||
x-transition
|
||||
class="text-green-400 px-2 py-1 text-xs text-center bg-green-500/10 border border-green-500/30 rounded"
|
||||
class="text-[var(--color-success)] px-2 py-1 text-xs text-center bg-[var(--color-success-light)] border border-[var(--color-success-light)] rounded"
|
||||
>
|
||||
Updated!
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-2 py-1 text-xs rounded text-[#101827] bg-[#38BDF8] hover:bg-[#38BDF8]/90 transition-colors font-medium"
|
||||
class="px-2 py-1 text-xs rounded text-[var(--color-bg-primary)] bg-[var(--color-primary)] hover:bg-[var(--color-primary)]/90 transition-colors font-medium"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
@@ -912,19 +913,19 @@ SOFTWARE.
|
||||
<!-- Generation Parameters -->
|
||||
<button
|
||||
@click="showParamsForm = !showParamsForm"
|
||||
class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] transition-colors"
|
||||
class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"
|
||||
>
|
||||
<span><i class="fa-solid fa-sliders mr-1.5 text-[#38BDF8]"></i> Generation Parameters</span>
|
||||
<span><i class="fa-solid fa-sliders mr-1.5 text-[var(--color-primary)]"></i> Generation Parameters</span>
|
||||
<i :class="showParamsForm ? 'fa-chevron-up' : 'fa-chevron-down'" class="fa-solid text-[10px]"></i>
|
||||
</button>
|
||||
|
||||
<div x-show="showParamsForm" class="p-2 bg-[#1E293B] border border-[#38BDF8]/20 rounded pl-4 border-l-2 border-[#1E293B] overflow-hidden">
|
||||
<div x-show="showParamsForm" class="p-2 bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded pl-4 border-l-2 border-[var(--color-bg-secondary)] overflow-hidden">
|
||||
<div class="flex flex-col space-y-3">
|
||||
<!-- Temperature -->
|
||||
<div class="space-y-1 min-w-0">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<label class="text-xs text-[#94A3B8] flex-shrink-0">Temperature</label>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.temperature !== null && $store.chat.activeChat()?.temperature !== undefined) ? $store.chat.activeChat().temperature.toFixed(2) : 'Default'"></span>
|
||||
<label class="text-xs text-[var(--color-text-secondary)] flex-shrink-0">Temperature</label>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.temperature !== null && $store.chat.activeChat()?.temperature !== undefined) ? $store.chat.activeChat().temperature.toFixed(2) : 'Default'"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<input
|
||||
@@ -932,27 +933,27 @@ SOFTWARE.
|
||||
min="0"
|
||||
max="2"
|
||||
step="0.01"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[#101827] rounded-lg appearance-none cursor-pointer accent-[#38BDF8]"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[var(--color-bg-primary)] rounded-lg appearance-none cursor-pointer accent-[var(--color-primary)]"
|
||||
:value="$store.chat.activeChat()?.temperature ?? 1.0"
|
||||
@input="if ($store.chat.activeChat()) { $store.chat.activeChat().temperature = parseFloat($event.target.value); $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
/>
|
||||
<button
|
||||
@click="if ($store.chat.activeChat()) { $store.chat.activeChat().temperature = null; $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
title="Reset to default"
|
||||
x-show="$store.chat.activeChat()?.temperature !== null && $store.chat.activeChat()?.temperature !== undefined"
|
||||
>
|
||||
<i class="fa-solid fa-rotate-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-[10px] text-[#94A3B8]">Controls randomness (0 = deterministic, 2 = very creative)</p>
|
||||
<p class="text-[10px] text-[var(--color-text-secondary)]">Controls randomness (0 = deterministic, 2 = very creative)</p>
|
||||
</div>
|
||||
|
||||
<!-- Top P -->
|
||||
<div class="space-y-1 min-w-0">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<label class="text-xs text-[#94A3B8] flex-shrink-0">Top P</label>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.topP !== null && $store.chat.activeChat()?.topP !== undefined) ? $store.chat.activeChat().topP.toFixed(2) : 'Default'"></span>
|
||||
<label class="text-xs text-[var(--color-text-secondary)] flex-shrink-0">Top P</label>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.topP !== null && $store.chat.activeChat()?.topP !== undefined) ? $store.chat.activeChat().topP.toFixed(2) : 'Default'"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<input
|
||||
@@ -960,27 +961,27 @@ SOFTWARE.
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[#101827] rounded-lg appearance-none cursor-pointer accent-[#38BDF8]"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[var(--color-bg-primary)] rounded-lg appearance-none cursor-pointer accent-[var(--color-primary)]"
|
||||
:value="$store.chat.activeChat()?.topP ?? 0.9"
|
||||
@input="if ($store.chat.activeChat()) { $store.chat.activeChat().topP = parseFloat($event.target.value); $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
/>
|
||||
<button
|
||||
@click="if ($store.chat.activeChat()) { $store.chat.activeChat().topP = null; $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
title="Reset to default"
|
||||
x-show="$store.chat.activeChat()?.topP !== null && $store.chat.activeChat()?.topP !== undefined"
|
||||
>
|
||||
<i class="fa-solid fa-rotate-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-[10px] text-[#94A3B8]">Nucleus sampling threshold (0-1)</p>
|
||||
<p class="text-[10px] text-[var(--color-text-secondary)]">Nucleus sampling threshold (0-1)</p>
|
||||
</div>
|
||||
|
||||
<!-- Top K -->
|
||||
<div class="space-y-1 min-w-0">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<label class="text-xs text-[#94A3B8] flex-shrink-0">Top K</label>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.topK !== null && $store.chat.activeChat()?.topK !== undefined) ? $store.chat.activeChat().topK : 'Default'"></span>
|
||||
<label class="text-xs text-[var(--color-text-secondary)] flex-shrink-0">Top K</label>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium flex-shrink-0" x-text="($store.chat.activeChat()?.topK !== null && $store.chat.activeChat()?.topK !== undefined) ? $store.chat.activeChat().topK : 'Default'"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<input
|
||||
@@ -988,20 +989,20 @@ SOFTWARE.
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[#101827] rounded-lg appearance-none cursor-pointer accent-[#38BDF8]"
|
||||
class="flex-1 min-w-0 h-1.5 bg-[var(--color-bg-primary)] rounded-lg appearance-none cursor-pointer accent-[var(--color-primary)]"
|
||||
:value="$store.chat.activeChat()?.topK ?? 40"
|
||||
@input="if ($store.chat.activeChat()) { $store.chat.activeChat().topK = parseInt($event.target.value); $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
/>
|
||||
<button
|
||||
@click="if ($store.chat.activeChat()) { $store.chat.activeChat().topK = null; $store.chat.activeChat().updatedAt = Date.now(); autoSaveChats(); }"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors text-xs px-2 py-1 flex-shrink-0"
|
||||
title="Reset to default"
|
||||
x-show="$store.chat.activeChat()?.topK !== null && $store.chat.activeChat()?.topK !== undefined"
|
||||
>
|
||||
<i class="fa-solid fa-rotate-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-[10px] text-[#94A3B8]">Limit sampling to top K tokens (0 = disabled)</p>
|
||||
<p class="text-[10px] text-[var(--color-text-secondary)]">Limit sampling to top K tokens (0 = disabled)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1015,30 +1016,30 @@ SOFTWARE.
|
||||
:class="sidebarOpen ? 'ml-56' : 'ml-0'">
|
||||
|
||||
<!-- Chat header with toggle button -->
|
||||
<div class="border-b border-[#1E293B] p-4 flex items-center justify-between">
|
||||
<div class="border-b border-[var(--color-bg-secondary)] p-4 flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<!-- Sidebar toggle button moved to be the first element in the header and with clear styling -->
|
||||
<button
|
||||
@click="sidebarOpen = !sidebarOpen"
|
||||
class="mr-4 text-[#94A3B8] hover:text-[#E5E7EB] focus:outline-none bg-[#1E293B] hover:bg-[#1E293B]/80 p-2 rounded transition-colors"
|
||||
class="mr-4 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] focus:outline-none bg-[var(--color-bg-secondary)] hover:bg-[var(--color-bg-secondary)]/80 p-2 rounded transition-colors"
|
||||
style="min-width: 36px;"
|
||||
title="Toggle settings">
|
||||
<i class="fa-solid" :class="sidebarOpen ? 'fa-chevron-left' : 'fa-bars'"></i>
|
||||
</button>
|
||||
|
||||
<div class="flex items-center">
|
||||
<i class="fa-solid fa-comments mr-2 text-[#38BDF8]"></i>
|
||||
<i class="fa-solid fa-comments mr-2 text-[var(--color-primary)]"></i>
|
||||
{{ if $model }}
|
||||
{{ $galleryConfig:= index $allGalleryConfigs $model}}
|
||||
{{ if $galleryConfig }}
|
||||
{{ if $galleryConfig.Icon }}<img src="{{$galleryConfig.Icon}}" class="rounded-lg w-8 h-8 mr-2">{{end}}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<h1 class="text-lg font-semibold text-[#E5E7EB]">
|
||||
<h1 class="text-lg font-semibold text-[var(--color-text-primary)]">
|
||||
Chat {{ if .Model }} with {{.Model}} {{ end }}
|
||||
</h1>
|
||||
<!-- Loading indicator next to model name -->
|
||||
<div id="header-loading-indicator" class="ml-3 text-[#38BDF8]" style="display: none;">
|
||||
<div id="header-loading-indicator" class="ml-3 text-[var(--color-primary)]" style="display: none;">
|
||||
<i class="fas fa-spinner fa-spin text-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1049,7 +1050,7 @@ SOFTWARE.
|
||||
@click="if (confirm('Clear all messages from this conversation? This action cannot be undone.')) { $store.chat.clear(); showClearAlert = true; setTimeout(() => showClearAlert = false, 3000); }"
|
||||
id="clear"
|
||||
title="Clear current chat history"
|
||||
class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors p-2 rounded hover:bg-[#1E293B]"
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors p-2 rounded hover:bg-[var(--color-bg-secondary)]"
|
||||
x-show="$store.chat.activeChat() && ($store.chat.activeChat()?.history?.length || 0) > 0">
|
||||
<i class="fa-solid fa-broom"></i>
|
||||
</button>
|
||||
@@ -1064,10 +1065,10 @@ SOFTWARE.
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="fixed top-20 right-4 z-50 max-w-sm pointer-events-none">
|
||||
<div class="bg-[#38BDF8]/20 border border-[#38BDF8]/40 rounded-lg p-3 shadow-lg backdrop-blur-sm">
|
||||
<div class="bg-[var(--color-primary)]/20 border border-[var(--color-primary-border)]/40 rounded-lg p-3 shadow-lg backdrop-blur-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fa-solid fa-check-circle text-[#38BDF8]"></i>
|
||||
<span class="text-sm text-[#E5E7EB] font-medium">Chat history cleared successfully</span>
|
||||
<i class="fa-solid fa-check-circle text-[var(--color-primary)]"></i>
|
||||
<span class="text-sm text-[var(--color-text-primary)] font-medium">Chat history cleared successfully</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1075,12 +1076,12 @@ SOFTWARE.
|
||||
|
||||
<!-- Chat messages area -->
|
||||
<div class="flex-1 p-4 overflow-auto" id="chat">
|
||||
<p id="usage" x-show="!$store.chat.activeChat() || ($store.chat.activeChat()?.history?.length || 0) === 0" class="text-[#94A3B8]">
|
||||
<p id="usage" x-show="!$store.chat.activeChat() || ($store.chat.activeChat()?.history?.length || 0) === 0" class="text-[var(--color-text-secondary)]">
|
||||
Start chatting with the AI by typing a prompt in the input field below and pressing Enter.<br>
|
||||
<ul class="list-disc list-inside mt-2 space-y-1">
|
||||
<li>For models that support images, you can upload an image by clicking the <i class="fa-solid fa-image text-[#38BDF8]"></i> icon.</li>
|
||||
<li>For models that support audio, you can upload an audio file by clicking the <i class="fa-solid fa-microphone text-[#38BDF8]"></i> icon.</li>
|
||||
<li>To send a text, markdown or PDF file, click the <i class="fa-solid fa-file text-[#38BDF8]"></i> icon.</li>
|
||||
<li>For models that support images, you can upload an image by clicking the <i class="fa-solid fa-image text-[var(--color-primary)]"></i> icon.</li>
|
||||
<li>For models that support audio, you can upload an audio file by clicking the <i class="fa-solid fa-microphone text-[var(--color-primary)]"></i> icon.</li>
|
||||
<li>To send a text, markdown or PDF file, click the <i class="fa-solid fa-file text-[var(--color-primary)]"></i> icon.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<div id="messages" class="max-w-3xl mx-auto space-y-2" :key="$store.chat.activeChatId">
|
||||
@@ -1090,28 +1091,28 @@ SOFTWARE.
|
||||
<template x-if="message.role === 'reasoning' || message.role === 'thinking'">
|
||||
<div class="flex items-start space-x-2 mb-1">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[#38BDF8]/10 text-[#94A3B8] border border-[#38BDF8]/30">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[var(--color-primary)]/10 text-[var(--color-text-secondary)] border border-[var(--color-primary-border)]/30">
|
||||
<button
|
||||
@click="message.expanded = !message.expanded"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[#38BDF8]/20 rounded p-2 transition-colors"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[var(--color-primary)]/20 rounded p-2 transition-colors"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<i :class="message.role === 'thinking' ? 'fa-solid fa-brain' : 'fa-solid fa-lightbulb'" class="text-[#38BDF8]"></i>
|
||||
<span class="text-xs font-semibold text-[#38BDF8]" x-text="message.role === 'thinking' ? 'Thinking' : 'Reasoning'"></span>
|
||||
<span class="text-xs text-[#94A3B8]" x-show="message.content && message.content.length > 0" x-text="'(' + Math.ceil(message.content.length / 100) + ' lines)'"></span>
|
||||
<i :class="message.role === 'thinking' ? 'fa-solid fa-brain' : 'fa-solid fa-lightbulb'" class="text-[var(--color-primary)]"></i>
|
||||
<span class="text-xs font-semibold text-[var(--color-primary)]" x-text="message.role === 'thinking' ? 'Thinking' : 'Reasoning'"></span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]" x-show="message.content && message.content.length > 0" x-text="'(' + Math.ceil(message.content.length / 100) + ' lines)'"></span>
|
||||
</div>
|
||||
<i
|
||||
class="fa-solid text-[#38BDF8] transition-transform text-xs"
|
||||
class="fa-solid text-[var(--color-primary)] transition-transform text-xs"
|
||||
:class="message.expanded ? 'fa-chevron-up' : 'fa-chevron-down'"
|
||||
></i>
|
||||
</button>
|
||||
<div
|
||||
x-show="message.expanded"
|
||||
x-transition
|
||||
class="mt-2 pt-2 border-t border-[#38BDF8]/20"
|
||||
class="mt-2 pt-2 border-t border-[var(--color-primary-border)]/20"
|
||||
>
|
||||
<div
|
||||
class="text-[#E5E7EB] text-sm max-h-96 overflow-auto"
|
||||
class="text-[var(--color-text-primary)] text-sm max-h-96 overflow-auto"
|
||||
x-html="message.html"
|
||||
data-thinking-box
|
||||
x-effect="if (message.expanded && message.html) { setTimeout(() => { if ($el.scrollHeight > $el.clientHeight) { $el.scrollTo({ top: $el.scrollHeight, behavior: 'smooth' }); } }, 50); }"
|
||||
@@ -1126,27 +1127,27 @@ SOFTWARE.
|
||||
<template x-if="message.role === 'tool_call'">
|
||||
<div class="flex items-start space-x-2 mb-1">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[#8B5CF6]/10 text-[#94A3B8] border border-[#8B5CF6]/30">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[var(--color-accent)]/10 text-[var(--color-text-secondary)] border border-[var(--color-accent-border)]/30">
|
||||
<button
|
||||
@click="message.expanded = !message.expanded"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[#8B5CF6]/20 rounded p-2 transition-colors"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[var(--color-accent)]/20 rounded p-2 transition-colors"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<i class="fa-solid fa-wrench text-[#8B5CF6]"></i>
|
||||
<span class="text-xs font-semibold text-[#8B5CF6]">Tool Call</span>
|
||||
<span class="text-xs text-[#94A3B8]" x-text="getToolName(message.content)"></span>
|
||||
<i class="fa-solid fa-wrench text-[var(--color-accent)]"></i>
|
||||
<span class="text-xs font-semibold text-[var(--color-accent)]">Tool Call</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]" x-text="getToolName(message.content)"></span>
|
||||
</div>
|
||||
<i
|
||||
class="fa-solid text-[#8B5CF6] transition-transform text-xs"
|
||||
class="fa-solid text-[var(--color-accent)] transition-transform text-xs"
|
||||
:class="message.expanded ? 'fa-chevron-up' : 'fa-chevron-down'"
|
||||
></i>
|
||||
</button>
|
||||
<div
|
||||
x-show="message.expanded"
|
||||
x-transition
|
||||
class="mt-2 pt-2 border-t border-[#8B5CF6]/20"
|
||||
class="mt-2 pt-2 border-t border-[var(--color-accent-border)]/20"
|
||||
>
|
||||
<div class="text-[#E5E7EB] text-xs max-h-96 overflow-auto tool-call-content"
|
||||
<div class="text-[var(--color-text-primary)] text-xs max-h-96 overflow-auto tool-call-content"
|
||||
x-html="message.html"
|
||||
x-effect="if (message.expanded && window.hljs) { setTimeout(() => { $el.querySelectorAll('pre code.language-json').forEach(block => { if (!block.classList.contains('hljs')) window.hljs.highlightElement(block); }); }, 50); }"></div>
|
||||
</div>
|
||||
@@ -1159,27 +1160,27 @@ SOFTWARE.
|
||||
<template x-if="message.role === 'tool_result'">
|
||||
<div class="flex items-start space-x-2 mb-1">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[#10B981]/10 text-[#94A3B8] border border-[#10B981]/30">
|
||||
<div class="p-2 flex-1 rounded-lg bg-[var(--color-success)]/10 text-[var(--color-text-secondary)] border border-[var(--color-success)]/30">
|
||||
<button
|
||||
@click="message.expanded = !message.expanded"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[#10B981]/20 rounded p-2 transition-colors"
|
||||
class="w-full flex items-center justify-between text-left hover:bg-[var(--color-success)]/20 rounded p-2 transition-colors"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<i class="fa-solid fa-check-circle text-[#10B981]"></i>
|
||||
<span class="text-xs font-semibold text-[#10B981]">Tool Result</span>
|
||||
<span class="text-xs text-[#94A3B8]" x-text="getToolName(message.content) || 'Success'"></span>
|
||||
<i class="fa-solid fa-check-circle text-[var(--color-success)]"></i>
|
||||
<span class="text-xs font-semibold text-[var(--color-success)]">Tool Result</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]" x-text="getToolName(message.content) || 'Success'"></span>
|
||||
</div>
|
||||
<i
|
||||
class="fa-solid text-[#10B981] transition-transform text-xs"
|
||||
class="fa-solid text-[var(--color-success)] transition-transform text-xs"
|
||||
:class="message.expanded ? 'fa-chevron-up' : 'fa-chevron-down'"
|
||||
></i>
|
||||
</button>
|
||||
<div
|
||||
x-show="message.expanded"
|
||||
x-transition
|
||||
class="mt-2 pt-2 border-t border-[#10B981]/20"
|
||||
class="mt-2 pt-2 border-t border-[var(--color-success)]/20"
|
||||
>
|
||||
<div class="text-[#E5E7EB] text-xs max-h-96 overflow-auto tool-result-content"
|
||||
<div class="text-[var(--color-text-primary)] text-xs max-h-96 overflow-auto tool-result-content"
|
||||
x-html="formatToolResult(message.content)"
|
||||
x-effect="if (message.expanded && window.hljs) { setTimeout(() => { $el.querySelectorAll('pre code.language-json').forEach(block => { if (!block.classList.contains('hljs')) window.hljs.highlightElement(block); }); }, 50); }"></div>
|
||||
</div>
|
||||
@@ -1195,8 +1196,8 @@ SOFTWARE.
|
||||
<template x-if="message.role === 'user'">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="flex flex-col flex-1 items-end">
|
||||
<span class="text-xs font-semibold text-[#94A3B8] mb-1">You</span>
|
||||
<div class="p-3 flex-1 rounded-lg bg-gradient-to-br from-[#1E293B] to-[#101827] text-[#E5E7EB] border border-[#38BDF8]/20 shadow-lg" x-html="message.html"></div>
|
||||
<span class="text-xs font-semibold text-[var(--color-text-secondary)] mb-1">You</span>
|
||||
<div class="p-3 flex-1 rounded-lg bg-[var(--color-bg-secondary)] text-[var(--color-text-primary)] border border-[var(--color-primary-border)]/20 shadow-lg" x-html="message.html"></div>
|
||||
<template x-if="message.image && message.image.length > 0">
|
||||
<div class="mt-2 space-y-2">
|
||||
<template x-for="(img, index) in message.image" :key="index">
|
||||
@@ -1220,13 +1221,13 @@ SOFTWARE.
|
||||
<template x-if="message.role != 'user' && message.role != 'thinking' && message.role != 'reasoning' && message.role != 'tool_call' && message.role != 'tool_result'">
|
||||
<div class="flex items-center space-x-2">
|
||||
{{ if $galleryConfig }}
|
||||
{{ if $galleryConfig.Icon }}<img src="{{$galleryConfig.Icon}}" class="rounded-lg mt-2 max-w-8 max-h-8 border border-[#38BDF8]/20">{{end}}
|
||||
{{ if $galleryConfig.Icon }}<img src="{{$galleryConfig.Icon}}" class="rounded-lg mt-2 max-w-8 max-h-8 border border-[var(--color-primary-border)]/20">{{end}}
|
||||
{{ end }}
|
||||
<div class="flex flex-col flex-1">
|
||||
<span class="text-xs font-semibold text-[#94A3B8] mb-1">{{if .Model}}{{.Model}}{{else}}Assistant{{end}}</span>
|
||||
<div class="flex-1 text-[#E5E7EB] flex items-center space-x-2 min-w-0">
|
||||
<div class="p-3 rounded-lg bg-gradient-to-br from-[#1E293B] to-[#101827] border border-[#8B5CF6]/20 shadow-lg max-w-full overflow-x-auto overflow-wrap-anywhere" x-html="message.html"></div>
|
||||
<button @click="copyToClipboard(message.html)" title="Copy to clipboard" class="text-[#94A3B8] hover:text-[#38BDF8] transition-colors p-1 flex-shrink-0">
|
||||
<span class="text-xs font-semibold text-[var(--color-text-secondary)] mb-1">{{if .Model}}{{.Model}}{{else}}Assistant{{end}}</span>
|
||||
<div class="flex-1 text-[var(--color-text-primary)] flex items-center space-x-2 min-w-0">
|
||||
<div class="p-3 rounded-lg bg-[var(--color-bg-secondary)] border border-[var(--color-accent-border)]/20 shadow-lg max-w-full overflow-x-auto overflow-wrap-anywhere" x-html="message.html"></div>
|
||||
<button @click="copyToClipboard(message.html)" title="Copy to clipboard" class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors p-1 flex-shrink-0">
|
||||
<i class="fa-solid fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1253,7 +1254,7 @@ SOFTWARE.
|
||||
{{ else }}
|
||||
<i
|
||||
class="fa-solid h-8 w-8"
|
||||
:class="message.role === 'user' ? 'fa-user text-[#38BDF8]' : 'fa-robot text-[#8B5CF6]'"
|
||||
:class="message.role === 'user' ? 'fa-user text-[var(--color-primary)]' : 'fa-robot text-[var(--color-accent)]'"
|
||||
></i>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -1264,18 +1265,18 @@ SOFTWARE.
|
||||
|
||||
|
||||
<!-- Chat Input -->
|
||||
<div class="p-4 border-t border-[#1E293B]" x-data="{ inputValue: '', shiftPressed: false, attachedFiles: [] }">
|
||||
<div class="p-4 border-t border-[var(--color-bg-secondary)]" x-data="{ inputValue: '', shiftPressed: false, attachedFiles: [] }">
|
||||
<form id="prompt" action="chat/{{.Model}}" method="get" @submit.prevent="submitPrompt" class="max-w-3xl mx-auto">
|
||||
<!-- Attachment Tags - Show above input when files are attached -->
|
||||
<div x-show="attachedFiles.length > 0" class="mb-3 flex flex-wrap gap-2 items-center">
|
||||
<template x-for="(file, index) in attachedFiles" :key="index">
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm bg-[#38BDF8]/20 border border-[#38BDF8]/40 text-[#E5E7EB]">
|
||||
<i :class="file.type === 'image' ? 'fa-solid fa-image' : file.type === 'audio' ? 'fa-solid fa-microphone' : 'fa-solid fa-file'" class="text-[#38BDF8]"></i>
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm bg-[var(--color-primary)]/20 border border-[var(--color-primary-border)]/40 text-[var(--color-text-primary)]">
|
||||
<i :class="file.type === 'image' ? 'fa-solid fa-image' : file.type === 'audio' ? 'fa-solid fa-microphone' : 'fa-solid fa-file'" class="text-[var(--color-primary)]"></i>
|
||||
<span x-text="file.name" class="max-w-[200px] truncate"></span>
|
||||
<button
|
||||
type="button"
|
||||
@click="attachedFiles.splice(index, 1); removeFileFromInput(file.type, file.name)"
|
||||
class="ml-1 text-[#94A3B8] hover:text-[#E5E7EB] transition-colors"
|
||||
class="ml-1 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors"
|
||||
title="Remove attachment"
|
||||
>
|
||||
<i class="fa-solid fa-times text-xs"></i>
|
||||
@@ -1287,62 +1288,63 @@ SOFTWARE.
|
||||
<!-- Token Usage and Context Window - Compact above input -->
|
||||
<div class="mb-3 flex items-center justify-between gap-4 text-xs">
|
||||
<!-- Token Usage -->
|
||||
<div class="flex items-center gap-3 text-[#94A3B8]">
|
||||
<div class="flex items-center gap-3 text-[var(--color-text-secondary)]">
|
||||
<div class="flex items-center gap-1">
|
||||
<i class="fas fa-chart-line text-[#38BDF8]"></i>
|
||||
<i class="fas fa-chart-line text-[var(--color-primary)]"></i>
|
||||
<span>Prompt:</span>
|
||||
<span class="text-[#E5E7EB] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.promptTokens || 0)"></span>
|
||||
<span class="text-[var(--color-text-primary)] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.promptTokens || 0)"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>Completion:</span>
|
||||
<span class="text-[#E5E7EB] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.completionTokens || 0)"></span>
|
||||
<span class="text-[var(--color-text-primary)] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.completionTokens || 0)"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 border-l border-[#1E293B] pl-3">
|
||||
<span class="text-[#38BDF8] font-semibold">Total:</span>
|
||||
<span class="text-[#E5E7EB] font-bold" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.totalTokens || 0)"></span>
|
||||
<div class="flex items-center gap-1 border-l border-[var(--color-bg-secondary)] pl-3">
|
||||
<span class="text-[var(--color-primary)] font-semibold">Total:</span>
|
||||
<span class="text-[var(--color-text-primary)] font-bold" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.totalTokens || 0)"></span>
|
||||
</div>
|
||||
<!-- Tokens per second display -->
|
||||
<div id="tokens-per-second-container" class="flex items-center gap-1 border-l border-[#1E293B] pl-3">
|
||||
<i class="fas fa-tachometer-alt text-[#38BDF8]"></i>
|
||||
<span id="tokens-per-second" class="text-[#E5E7EB] font-medium">-</span>
|
||||
<span id="max-tokens-per-second-badge" class="ml-2 px-1.5 py-0.5 text-[10px] bg-[#38BDF8]/20 text-[#38BDF8] rounded border border-[#38BDF8]/30 hidden"></span>
|
||||
<div id="tokens-per-second-container" class="flex items-center gap-1 border-l border-[var(--color-bg-secondary)] pl-3">
|
||||
<i class="fas fa-tachometer-alt text-[var(--color-primary)]"></i>
|
||||
<span id="tokens-per-second" class="text-[var(--color-text-primary)] font-medium">-</span>
|
||||
<span id="max-tokens-per-second-badge" class="ml-2 px-1.5 py-0.5 text-[10px] bg-[var(--color-primary)]/20 text-[var(--color-primary)] rounded border border-[var(--color-primary-border)]/30 hidden"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Context Window -->
|
||||
<template x-if="$store.chat.activeChat()?.contextSize && $store.chat.activeChat().contextSize > 0">
|
||||
<div class="flex items-center gap-2 text-[#94A3B8]">
|
||||
<i class="fas fa-database text-[#38BDF8]"></i>
|
||||
<div class="flex items-center gap-2 text-[var(--color-text-secondary)]">
|
||||
<i class="fas fa-database text-[var(--color-primary)]"></i>
|
||||
<span>
|
||||
<span class="text-[#E5E7EB] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.totalTokens || 0)"></span>
|
||||
<span class="text-[var(--color-text-primary)] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.tokenUsage?.totalTokens || 0)"></span>
|
||||
/
|
||||
<span class="text-[#E5E7EB] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.contextSize || 0)"></span>
|
||||
<span class="text-[var(--color-text-primary)] font-medium" x-text="new Intl.NumberFormat().format($store.chat.activeChat()?.contextSize || 0)"></span>
|
||||
</span>
|
||||
<div class="w-16 bg-[#101827] rounded-full h-1.5 overflow-hidden border border-[#1E293B]">
|
||||
<div class="w-16 bg-[var(--color-bg-primary)] rounded-full h-1.5 overflow-hidden border border-[var(--color-bg-secondary)]">
|
||||
<div class="h-full rounded-full transition-all duration-300 ease-out"
|
||||
:class="{
|
||||
'bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]': $store.chat.getContextUsagePercent() < 80,
|
||||
'bg-gradient-to-r from-[var(--color-primary)] to-[var(--color-accent)]': $store.chat.getContextUsagePercent() < 80,
|
||||
'bg-gradient-to-r from-yellow-500 to-orange-500': $store.chat.getContextUsagePercent() >= 80 && $store.chat.getContextUsagePercent() < 95,
|
||||
'bg-gradient-to-r from-red-500 to-red-600': $store.chat.getContextUsagePercent() >= 95
|
||||
}"
|
||||
:style="'width: ' + Math.min(100, $store.chat.getContextUsagePercent()) + '%'">
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-[#94A3B8]" x-text="Math.round($store.chat.getContextUsagePercent()) + '%'"></span>
|
||||
<span x-show="$store.chat.getContextUsagePercent() >= 80" class="text-yellow-400">
|
||||
<span class="text-[var(--color-text-secondary)]" x-text="Math.round($store.chat.getContextUsagePercent()) + '%'"></span>
|
||||
<span x-show="$store.chat.getContextUsagePercent() >= 80" class="text-[var(--color-warning)]">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="relative w-full bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl shadow-lg focus-within:ring-2 focus-within:ring-[#38BDF8]/50 focus-within:border-[#38BDF8] transition-all duration-200">
|
||||
<div class="relative w-full">
|
||||
<textarea
|
||||
id="input"
|
||||
name="input"
|
||||
x-model="inputValue"
|
||||
class="input w-full p-3 pr-16 resize-none border-0"
|
||||
placeholder="Send a message..."
|
||||
class="p-3 pr-16 w-full bg-[#1E293B] text-[#E5E7EB] placeholder-[#94A3B8] focus:outline-none resize-none border-0 rounded-xl transition-colors duration-200"
|
||||
class="p-3 pr-16 w-full bg-[var(--color-bg-secondary)] text-[var(--color-text-primary)] placeholder-[var(--color-text-secondary)] focus:outline-none resize-none border-0 rounded-xl transition-colors duration-200"
|
||||
required
|
||||
@keydown.shift="shiftPressed = true"
|
||||
@keyup.shift="shiftPressed = false"
|
||||
@@ -1352,19 +1354,19 @@ SOFTWARE.
|
||||
<button
|
||||
type="button"
|
||||
onclick="document.getElementById('input_image').click()"
|
||||
class="fa-solid fa-image text-[#94A3B8] absolute right-12 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-image text-[var(--color-text-secondary)] absolute right-12 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Attach images"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
onclick="document.getElementById('input_audio').click()"
|
||||
class="fa-solid fa-microphone text-[#94A3B8] absolute right-20 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-microphone text-[var(--color-text-secondary)] absolute right-20 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Attach an audio file"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
onclick="document.getElementById('input_file').click()"
|
||||
class="fa-solid fa-file text-[#94A3B8] absolute right-28 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-file text-[var(--color-text-secondary)] absolute right-28 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Upload text, markdown or PDF file"
|
||||
></button>
|
||||
|
||||
@@ -1375,7 +1377,7 @@ SOFTWARE.
|
||||
id="stop-button"
|
||||
type="button"
|
||||
onclick="stopRequest()"
|
||||
class="text-lg p-2 text-red-400 hover:text-red-500 transition-colors duration-200"
|
||||
class="text-lg p-2 text-[var(--color-error)] hover:text-[var(--color-error)] transition-colors duration-200"
|
||||
style="display: none;"
|
||||
title="Stop request"
|
||||
>
|
||||
@@ -1386,7 +1388,7 @@ SOFTWARE.
|
||||
<button
|
||||
id="send-button"
|
||||
type="submit"
|
||||
class="text-lg p-2 text-[#94A3B8] hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="text-lg p-2 text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Send message (Enter)"
|
||||
>
|
||||
<i class="fa-solid fa-paper-plane"></i>
|
||||
@@ -1504,7 +1506,7 @@ SOFTWARE.
|
||||
|
||||
// Format the JSON nicely
|
||||
const formatted = JSON.stringify(parsed, null, 2);
|
||||
return DOMPurify.sanitize('<pre class="bg-[#101827] p-3 rounded border border-[#10B981]/20 overflow-x-auto"><code class="language-json">' + formatted + '</code></pre>');
|
||||
return DOMPurify.sanitize('<pre class="bg-[var(--color-bg-primary)] p-3 rounded border border-[var(--color-success)]/20 overflow-x-auto"><code class="language-json">' + formatted + '</code></pre>');
|
||||
} catch (e) {
|
||||
// If not JSON, try to format as markdown or plain text
|
||||
try {
|
||||
@@ -1534,7 +1536,7 @@ SOFTWARE.
|
||||
try {
|
||||
const parsed = JSON.parse(jsonStr);
|
||||
const formatted = JSON.stringify(parsed, null, 2);
|
||||
return DOMPurify.sanitize('<pre class="bg-[#101827] p-3 rounded border border-[#10B981]/20 overflow-x-auto"><code class="language-json">' + formatted + '</code></pre>');
|
||||
return DOMPurify.sanitize('<pre class="bg-[var(--color-bg-primary)] p-3 rounded border border-[var(--color-success)]/20 overflow-x-auto"><code class="language-json">' + formatted + '</code></pre>');
|
||||
} catch (e2) {
|
||||
// Fall through to markdown
|
||||
}
|
||||
@@ -1544,7 +1546,7 @@ SOFTWARE.
|
||||
return DOMPurify.sanitize(marked.parse(content));
|
||||
} catch (e2) {
|
||||
// Last resort: plain text
|
||||
return DOMPurify.sanitize('<pre class="bg-[#101827] p-3 rounded border border-[#10B981]/20 overflow-x-auto text-xs">' + content.replace(/</g, '<').replace(/>/g, '>') + '</pre>');
|
||||
return DOMPurify.sanitize('<pre class="bg-[var(--color-bg-primary)] p-3 rounded border border-[var(--color-success)]/20 overflow-x-auto text-xs">' + content.replace(/</g, '<').replace(/>/g, '>') + '</pre>');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1813,18 +1815,18 @@ SOFTWARE.
|
||||
|
||||
.tool-call-content .hljs-keyword,
|
||||
.tool-result-content .hljs-keyword {
|
||||
color: #8B5CF6 !important;
|
||||
color: var(--color-accent) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tool-call-content .hljs-string,
|
||||
.tool-result-content .hljs-string {
|
||||
color: #10B981 !important;
|
||||
color: var(--color-success) !important;
|
||||
}
|
||||
|
||||
.tool-call-content .hljs-number,
|
||||
.tool-result-content .hljs-number {
|
||||
color: #38BDF8 !important;
|
||||
color: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.tool-call-content .hljs-literal,
|
||||
@@ -1839,12 +1841,12 @@ SOFTWARE.
|
||||
|
||||
.tool-call-content .hljs-property,
|
||||
.tool-result-content .hljs-property {
|
||||
color: #38BDF8 !important;
|
||||
color: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.tool-call-content .hljs-attr,
|
||||
.tool-result-content .hljs-attr {
|
||||
color: #8B5CF6 !important;
|
||||
color: var(--color-accent) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
<div class="mb-6 text-6xl text-red-400">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-red-400 to-red-600">
|
||||
{{if .ErrorCode}}{{.ErrorCode}}{{else}}Error{{end}}
|
||||
</span>
|
||||
<h1 class="hero-title mb-4" style="color: var(--color-error);">
|
||||
{{if .ErrorCode}}{{.ErrorCode}}{{else}}Error{{end}}
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8] mb-6">{{if .ErrorMessage}}{{.ErrorMessage}}{{else}}An unexpected error occurred{{end}}</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
|
||||
@@ -162,9 +162,8 @@
|
||||
<canvas id="networkCanvas"></canvas>
|
||||
<div class="text-overlay">
|
||||
<header class="text-center py-12">
|
||||
<h1 class="text-5xl font-bold text-gray-100">
|
||||
<h1 class="hero-title">
|
||||
<i class="fa-solid fa-circle-nodes mr-2"></i> Network Clusters Explorer
|
||||
|
||||
</h1>
|
||||
<p class="mt-4 text-lg">
|
||||
View the clusters and workers available in each network.
|
||||
@@ -188,7 +187,7 @@
|
||||
</div>
|
||||
<div class="flow-root">
|
||||
<!-- Toggle button for showing/hiding the form -->
|
||||
<button class="bg-red-600 hover:bg-blue-600 float-right mb-2 flex items-center px-4 py-2 rounded" @click="toggleForm()">
|
||||
<button class="btn-primary float-right mb-2" @click="toggleForm()">
|
||||
<!-- Conditional icon display -->
|
||||
<i :class="showForm ? 'fa-solid fa-times' : 'fa-solid fa-plus'" class="mr-2"></i>
|
||||
<span x-text="showForm ? 'Close' : 'Add New Network'"></span>
|
||||
@@ -196,20 +195,20 @@
|
||||
</div>
|
||||
<!-- Form for adding a new network -->
|
||||
<div class="form-container" x-show="showForm" @click.outside="showForm = false">
|
||||
<h2 class="text-3xl font-bold mb-4"><i class="fa-solid fa-plus"></i> Add New Network</h2>
|
||||
<h2 class="h2"><i class="fa-solid fa-plus"></i> Add New Network</h2>
|
||||
<div class="form-control">
|
||||
<label for="name">Network Name</label>
|
||||
<input type="text" id="name" x-model="newNetwork.name" placeholder="Enter network name" />
|
||||
<input type="text" id="name" x-model="newNetwork.name" placeholder="Enter network name" class="input" />
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label for="description">Description</label>
|
||||
<textarea id="description" x-model="newNetwork.description" placeholder="Enter description"></textarea>
|
||||
<textarea id="description" x-model="newNetwork.description" placeholder="Enter description" class="input"></textarea>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label for="token">Token</label>
|
||||
<textarea id="token" x-model="newNetwork.token" placeholder="Enter token"></textarea>
|
||||
<textarea id="token" x-model="newNetwork.token" placeholder="Enter token" class="input"></textarea>
|
||||
</div>
|
||||
<button @click="addNetwork"><i class="fa-solid fa-plus"></i> Add Network</button>
|
||||
<button @click="addNetwork" class="btn-primary"><i class="fa-solid fa-plus"></i> Add Network</button>
|
||||
<template x-if="errorMessage">
|
||||
<p class="error" x-text="errorMessage"></p>
|
||||
</template>
|
||||
@@ -248,7 +247,7 @@
|
||||
<p class="text-lg font-bold mb-4 mt-1"><i class="fa-solid fa-book mr-2"></i> Description</p>
|
||||
<p x-text="network.description"></p>
|
||||
</div>
|
||||
<h2 class="text-3xl font-bold mb-4 mt-4">Available Clusters in this network</h2>
|
||||
<h2 class="h2">Available Clusters in this network</h2>
|
||||
<template x-for="cluster in network.Clusters" :key="cluster.NetworkID + cluster.Type">
|
||||
<div class="cluster">
|
||||
<div class="cluster-title"></div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
{{template "views/partials/head" .}}
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
@@ -12,110 +12,104 @@
|
||||
<div class="w-full max-w-3xl mx-auto">
|
||||
{{ if eq (len .ModelsConfig) 0 }}
|
||||
<!-- No Models - Wizard Guide -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-12">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-[#8B5CF6]/10 border border-[#8B5CF6]/20 mb-6">
|
||||
<i class="text-[#8B5CF6] text-2xl fas fa-robot"></i>
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
No Models Installed
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h2 class="hero-title">
|
||||
No Models Installed
|
||||
</h2>
|
||||
<p class="text-xl text-[#94A3B8] mb-8">
|
||||
<p class="hero-subtitle">
|
||||
Get started with LocalAI by installing your first model. Choose from our gallery, import your own, or use the API to download models.
|
||||
</p>
|
||||
|
||||
<!-- Features Preview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-10">
|
||||
<div class="bg-[#101827] border border-[#38BDF8]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-images text-[#38BDF8] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Model Gallery</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Browse and install pre-configured models</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-purple-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-upload text-[#8B5CF6] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Import Models</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Upload your own model files</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-green-500/20 rounded-lg p-4">
|
||||
<div class="w-10 h-10 bg-green-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-code text-green-400 text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">API Download</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Use the API to download models programmatically</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features Preview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-[var(--color-primary-light)] rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-images text-[var(--color-primary)] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">Model Gallery</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Browse and install pre-configured models</p>
|
||||
</div>
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-[var(--color-accent-light)] rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-upload text-[var(--color-accent)] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">Import Models</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Upload your own model files</p>
|
||||
</div>
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-[var(--color-success-light)] rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-code text-[var(--color-success)] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[var(--color-text-primary)] mb-2">API Download</h3>
|
||||
<p class="text-xs text-[var(--color-text-secondary)]">Use the API to download models programmatically</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Setup Instructions -->
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-xl p-6 mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-rocket text-[#8B5CF6] mr-2"></i>
|
||||
How to Get Started
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">1</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Browse the Model Gallery</p>
|
||||
<p class="text-[#94A3B8] text-sm">Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">2</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Install a Model</p>
|
||||
<p class="text-[#94A3B8] text-sm">Click on a model from the gallery to install it, or use the import feature to upload your own model files.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[#8B5CF6]/20 flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[#8B5CF6] font-bold text-sm">3</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[#E5E7EB] font-medium mb-2">Start Chatting</p>
|
||||
<p class="text-[#94A3B8] text-sm">Once installed, return to this page to start chatting with your model or use the API to interact programmatically.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Setup Instructions -->
|
||||
<div class="card mb-6 text-left">
|
||||
<h3 class="text-lg font-bold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-rocket text-[var(--color-accent)] mr-2"></i>
|
||||
How to Get Started
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent-light)] flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">1</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Browse the Model Gallery</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/browse/"
|
||||
class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-images mr-2"></i>
|
||||
Browse Model Gallery
|
||||
</a>
|
||||
<a href="/import-model"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
Import Model
|
||||
</a>
|
||||
<a href="https://localai.io/basics/getting_started/" target="_blank"
|
||||
class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#8B5CF6]/20 text-[#E5E7EB] py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<i class="fas fa-graduation-cap mr-2"></i>
|
||||
Getting Started
|
||||
<i class="fas fa-external-link-alt ml-2 text-sm"></i>
|
||||
</a>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent-light)] flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">2</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Install a Model</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Click on a model from the gallery to install it, or use the import feature to upload your own model files.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--color-accent-light)] flex items-center justify-center mr-3 mt-0.5">
|
||||
<span class="text-[var(--color-accent)] font-bold text-sm">3</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-[var(--color-text-primary)] font-medium mb-2">Start Chatting</p>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm">Once installed, return to this page to start chatting with your model or use the API to interact programmatically.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-4 mb-8">
|
||||
<a href="/browse/" class="btn-primary">
|
||||
<i class="fas fa-images mr-2"></i>
|
||||
Browse Model Gallery
|
||||
</a>
|
||||
<a href="/import-model" class="btn-primary">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
Import Model
|
||||
</a>
|
||||
<a href="https://localai.io/basics/getting_started/" target="_blank" class="btn-secondary">
|
||||
<i class="fas fa-graduation-cap mr-2"></i>
|
||||
Getting Started
|
||||
<i class="fas fa-external-link-alt ml-2 text-sm"></i>
|
||||
</a>
|
||||
</div>
|
||||
{{ else }}
|
||||
<!-- Welcome Message -->
|
||||
<div class="text-center mb-12">
|
||||
<div class="mb-6 flex justify-center">
|
||||
<img src="static/logo.png" alt="LocalAI Logo" class="h-24 md:h-32 drop-shadow-[0_0_15px_rgba(56,189,248,0.3)]">
|
||||
<!-- Welcome Message / Hero Section -->
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<div class="mb-4 flex justify-center">
|
||||
<img src="static/logo.png" alt="LocalAI Logo" class="h-16 md:h-20">
|
||||
</div>
|
||||
<h1 class="hero-title">How can I help you today?</h1>
|
||||
<p class="hero-subtitle">Ask me anything, and I'll do my best to assist you.</p>
|
||||
</div>
|
||||
|
||||
<p class="text-lg text-[#94A3B8]">How can I help you today?</p>
|
||||
</div>
|
||||
|
||||
<!-- Chat Input Form -->
|
||||
@@ -309,21 +303,21 @@
|
||||
}">
|
||||
<!-- Model Selector with MCP Toggle -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-[#94A3B8] mb-2">Select Model</label>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-secondary)] mb-2">Select Model</label>
|
||||
<div class="flex items-center gap-3">
|
||||
<select
|
||||
x-model="selectedModel"
|
||||
@change="$nextTick(() => checkMCPAvailability())"
|
||||
class="flex-1 bg-[#1E293B] text-[#E5E7EB] border border-[#38BDF8]/20 focus:border-[#38BDF8] focus:ring-2 focus:ring-[#38BDF8]/50 rounded-lg p-3 appearance-none"
|
||||
class="input flex-1"
|
||||
required
|
||||
>
|
||||
<option value="" disabled class="text-[#94A3B8]">Select a model to chat with...</option>
|
||||
<option value="" disabled class="text-[var(--color-text-secondary)]">Select a model to chat with...</option>
|
||||
{{ range .ModelsConfig }}
|
||||
{{ $cfg := . }}
|
||||
{{ $hasMCP := or (ne $cfg.MCP.Servers "") (ne $cfg.MCP.Stdio "") }}
|
||||
{{ range .KnownUsecaseStrings }}
|
||||
{{ if eq . "FLAG_CHAT" }}
|
||||
<option value="{{$cfg.Name}}" data-has-mcp="{{if $hasMCP}}true{{else}}false{{end}}" class="bg-[#1E293B] text-[#E5E7EB]">{{$cfg.Name}}</option>
|
||||
<option value="{{$cfg.Name}}" data-has-mcp="{{if $hasMCP}}true{{else}}false{{end}}" class="bg-[var(--color-bg-secondary)] text-[var(--color-text-primary)]">{{$cfg.Name}}</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -332,12 +326,12 @@
|
||||
<!-- Compact MCP Toggle - Show only if MCP is available for selected model -->
|
||||
<div
|
||||
x-show="mcpAvailable"
|
||||
class="flex items-center gap-2 px-3 py-2 text-xs rounded text-[#E5E7EB] bg-[#1E293B] border border-[#38BDF8]/20 whitespace-nowrap">
|
||||
<i class="fa-solid fa-plug text-[#38BDF8] text-sm"></i>
|
||||
<span class="text-[#94A3B8]">MCP</span>
|
||||
class="flex items-center gap-2 px-3 py-2 text-xs rounded text-[var(--color-text-primary)] bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)] whitespace-nowrap">
|
||||
<i class="fa-solid fa-plug text-[var(--color-primary)] text-sm"></i>
|
||||
<span class="text-[var(--color-text-secondary)]">MCP</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer ml-1">
|
||||
<input type="checkbox" id="index_mcp_toggle" class="sr-only peer" x-model="mcpMode">
|
||||
<div class="w-9 h-5 bg-[#101827] peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-[#38BDF8]/30 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-[#1E293B] after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-[#38BDF8]"></div>
|
||||
<div class="w-9 h-5 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-[var(--color-primary-border)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-[var(--color-bg-secondary)] after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-[var(--color-primary)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -345,10 +339,10 @@
|
||||
<!-- MCP Mode Notification - Compact tooltip style -->
|
||||
<div
|
||||
x-show="mcpMode && mcpAvailable"
|
||||
class="mt-2 p-2 bg-[#38BDF8]/10 border border-[#38BDF8]/30 rounded text-[#94A3B8] text-xs">
|
||||
class="mt-2 p-2 bg-[var(--color-primary-light)] border border-[var(--color-primary-border)] rounded text-[var(--color-text-secondary)] text-xs">
|
||||
<div class="flex items-start space-x-2">
|
||||
<i class="fa-solid fa-info-circle text-[#38BDF8] mt-0.5 text-xs"></i>
|
||||
<p class="text-[#94A3B8]">Non-streaming mode active. Responses may take longer to process.</p>
|
||||
<i class="fa-solid fa-info-circle text-[var(--color-primary)] mt-0.5 text-xs"></i>
|
||||
<p class="text-[var(--color-text-secondary)]">Non-streaming mode active. Responses may take longer to process.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -358,13 +352,13 @@
|
||||
<!-- Attachment Tags - Show above input when files are attached -->
|
||||
<div x-show="attachedFiles.length > 0" class="mb-3 flex flex-wrap gap-2 items-center">
|
||||
<template x-for="(file, index) in attachedFiles" :key="index">
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm bg-[#38BDF8]/20 border border-[#38BDF8]/40 text-[#E5E7EB]">
|
||||
<i :class="file.type === 'image' ? 'fa-solid fa-image' : file.type === 'audio' ? 'fa-solid fa-microphone' : 'fa-solid fa-file'" class="text-[#38BDF8]"></i>
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm bg-[var(--color-primary-light)] border border-[var(--color-primary-border)] text-[var(--color-text-primary)]">
|
||||
<i :class="file.type === 'image' ? 'fa-solid fa-image' : file.type === 'audio' ? 'fa-solid fa-microphone' : 'fa-solid fa-file'" class="text-[var(--color-primary)]"></i>
|
||||
<span x-text="file.name" class="max-w-[200px] truncate"></span>
|
||||
<button
|
||||
type="button"
|
||||
@click="attachedFiles.splice(index, 1); removeAttachedFile(file.type, file.name)"
|
||||
class="ml-1 text-[#94A3B8] hover:text-[#E5E7EB] transition-colors"
|
||||
class="ml-1 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors"
|
||||
title="Remove attachment"
|
||||
>
|
||||
<i class="fa-solid fa-times text-xs"></i>
|
||||
@@ -373,11 +367,11 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="relative w-full bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl focus-within:ring-2 focus-within:ring-[#38BDF8]/50 focus-within:border-[#38BDF8] transition-all duration-200">
|
||||
<div class="relative w-full">
|
||||
<textarea
|
||||
x-model="inputValue"
|
||||
:placeholder="currentPlaceholder"
|
||||
class="p-3 pr-16 w-full bg-[#1E293B] text-[#E5E7EB] placeholder-[#94A3B8] focus:outline-none resize-none border-0 rounded-xl transition-colors duration-200"
|
||||
class="input p-3 pr-16 w-full resize-none border-0"
|
||||
required
|
||||
@keydown.shift="shiftPressed = true"
|
||||
@keyup.shift="shiftPressed = false"
|
||||
@@ -392,19 +386,19 @@
|
||||
<button
|
||||
type="button"
|
||||
@click="document.getElementById('index_input_image').click()"
|
||||
class="fa-solid fa-image text-[#94A3B8] absolute right-12 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-image text-[var(--color-text-secondary)] absolute right-12 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Attach images"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
@click="document.getElementById('index_input_audio').click()"
|
||||
class="fa-solid fa-microphone text-[#94A3B8] absolute right-20 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-microphone text-[var(--color-text-secondary)] absolute right-20 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Attach an audio file"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
@click="document.getElementById('index_input_file').click()"
|
||||
class="fa-solid fa-file text-[#94A3B8] absolute right-28 top-3 text-base p-1.5 hover:text-[#38BDF8] transition-colors duration-200"
|
||||
class="fa-solid fa-file text-[var(--color-text-secondary)] absolute right-28 top-3 text-base p-1.5 hover:text-[var(--color-primary)] transition-colors duration-200"
|
||||
title="Upload text, markdown or PDF file"
|
||||
></button>
|
||||
|
||||
@@ -413,7 +407,7 @@
|
||||
type="submit"
|
||||
:disabled="!selectedModel || (!inputValue.trim() && !currentPlaceholder.trim())"
|
||||
:class="!selectedModel || (!inputValue.trim() && !currentPlaceholder.trim()) ? 'opacity-50 cursor-not-allowed' : ''"
|
||||
class="text-lg p-2 text-[#94A3B8] hover:text-[#38BDF8] transition-colors duration-200 absolute right-3 top-3"
|
||||
class="text-lg p-2 text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors duration-200 absolute right-3 top-3"
|
||||
title="Send message (Enter)"
|
||||
>
|
||||
<i class="fa-solid fa-paper-plane"></i>
|
||||
@@ -450,22 +444,19 @@
|
||||
|
||||
<!-- Quick Links -->
|
||||
<div class="flex flex-wrap justify-center gap-3 mb-8">
|
||||
<a href="/manage"
|
||||
class="inline-flex items-center text-sm text-[#94A3B8] hover:text-[#E5E7EB] px-4 py-2 rounded-lg hover:bg-[#1E293B] transition-colors">
|
||||
<a href="/manage" class="btn-tertiary">
|
||||
<i class="fas fa-cog mr-2"></i>
|
||||
Installed Models and Backends
|
||||
</a>
|
||||
<a href="/import-model" class="inline-flex items-center text-sm text-[#94A3B8] hover:text-[#E5E7EB] px-4 py-2 rounded-lg hover:bg-[#1E293B] transition-colors">
|
||||
<a href="/import-model" class="btn-tertiary">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
Import Model
|
||||
</a>
|
||||
<a href="/browse/"
|
||||
class="inline-flex items-center text-sm text-[#94A3B8] hover:text-[#E5E7EB] px-4 py-2 rounded-lg hover:bg-[#1E293B] transition-colors">
|
||||
<a href="/browse/" class="btn-tertiary">
|
||||
<i class="fas fa-images mr-2"></i>
|
||||
Browse Gallery
|
||||
</a>
|
||||
<a href="https://localai.io" target="_blank"
|
||||
class="inline-flex items-center text-sm text-[#94A3B8] hover:text-[#E5E7EB] px-4 py-2 rounded-lg hover:bg-[#1E293B] transition-colors">
|
||||
<a href="https://localai.io" target="_blank" class="btn-tertiary">
|
||||
<i class="fas fa-book mr-2"></i>
|
||||
Documentation
|
||||
</a>
|
||||
@@ -473,7 +464,7 @@
|
||||
|
||||
<!-- Model Status Summary - Subtle -->
|
||||
{{ $loadedModels := .LoadedModels }}
|
||||
<div class="mb-8 flex items-center justify-center gap-2 text-xs text-[#94A3B8]"
|
||||
<div class="mb-8 flex items-center justify-center gap-2 text-xs text-[var(--color-text-secondary)]"
|
||||
x-data="{ stoppingAll: false, stopAllModels() { window.stopAllModels(this); }, stopModel(name) { window.stopModel(name); }, getLoadedCount() { return document.querySelectorAll('[data-loaded-model]').length; } }"
|
||||
x-show="getLoadedCount() > 0"
|
||||
style="display: none;">
|
||||
@@ -481,10 +472,10 @@
|
||||
<i class="fas fa-circle text-green-500 text-[10px]"></i>
|
||||
<span x-text="`${getLoadedCount()} model(s) loaded`"></span>
|
||||
</span>
|
||||
<span class="text-[#38BDF8]/40">•</span>
|
||||
<span class="text-[var(--color-primary)] opacity-40">•</span>
|
||||
{{ range .ModelsConfig }}
|
||||
{{ if index $loadedModels .Name }}
|
||||
<span class="inline-flex items-center gap-1 text-[#94A3B8] hover:text-[#E5E7EB] transition-colors" data-loaded-model>
|
||||
<span class="inline-flex items-center gap-1 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors" data-loaded-model>
|
||||
<span class="truncate max-w-[100px]">{{.Name}}</span>
|
||||
<button
|
||||
@click="stopModel('{{.Name}}')"
|
||||
@@ -496,7 +487,7 @@
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<span class="text-[#38BDF8]/40">•</span>
|
||||
<span class="text-[var(--color-primary)] opacity-40">•</span>
|
||||
<button
|
||||
@click="stopAllModels()"
|
||||
:disabled="stoppingAll"
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
|
||||
<div class="p-8">
|
||||
<div class="text-center mb-6">
|
||||
<h2 class="text-2xl font-bold text-[#E5E7EB]">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
Authorization Required
|
||||
</span>
|
||||
<h2 class="h2">
|
||||
Authorization Required
|
||||
</h2>
|
||||
<p class="text-[#94A3B8] mt-2">Please enter your access token to continue</p>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
{{template "views/partials/head" .}}
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
@@ -17,7 +17,7 @@
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
:class="notification.type === 'error' ? 'bg-red-500' : 'bg-green-500'"
|
||||
:class="notification.type === 'error' ? 'bg-red-500' : 'bg-[var(--color-success)]'"
|
||||
class="rounded-lg p-4 text-white flex items-start space-x-3">
|
||||
<div class="flex-shrink-0">
|
||||
<i :class="notification.type === 'error' ? 'fas fa-exclamation-circle' : 'fas fa-check-circle'" class="text-xl"></i>
|
||||
@@ -32,48 +32,45 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="container mx-auto px-4 py-6 flex-grow">
|
||||
<!-- Header -->
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-semibold text-[#E5E7EB] mb-1">
|
||||
Model & Backend Management
|
||||
</h1>
|
||||
<p class="text-sm text-[#94A3B8]">Manage your installed models and backends</p>
|
||||
</div>
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
<!-- Hero Header -->
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
Model & Backend Management
|
||||
</h1>
|
||||
<p class="hero-subtitle">Manage your installed models and backends</p>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="flex flex-wrap justify-center gap-3">
|
||||
<a href="browse" class="btn-primary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-images mr-1.5 text-[10px]"></i>
|
||||
<span>Model Gallery</span>
|
||||
</a>
|
||||
|
||||
<a href="/import-model" class="btn-primary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-plus mr-1.5 text-[10px]"></i>
|
||||
<span>Import Model</span>
|
||||
</a>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<a href="browse"
|
||||
class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<i class="fas fa-images mr-1.5 text-[10px]"></i>
|
||||
<span>Model Gallery</span>
|
||||
</a>
|
||||
|
||||
<a href="/import-model"
|
||||
class="inline-flex items-center bg-green-600 hover:bg-green-700 text-white py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<i class="fas fa-plus mr-1.5 text-[10px]"></i>
|
||||
<span>Import Model</span>
|
||||
</a>
|
||||
<button id="reload-models-btn" class="btn-primary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-sync-alt mr-1.5 text-[10px]"></i>
|
||||
<span>Update Models</span>
|
||||
</button>
|
||||
|
||||
<button id="reload-models-btn"
|
||||
class="inline-flex items-center bg-orange-600 hover:bg-orange-700 text-white py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<i class="fas fa-sync-alt mr-1.5 text-[10px]"></i>
|
||||
<span>Update Models</span>
|
||||
</button>
|
||||
<a href="/browse/backends" class="btn-secondary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-cogs mr-1.5 text-[10px]"></i>
|
||||
<span>Backend Gallery</span>
|
||||
</a>
|
||||
|
||||
<a href="/browse/backends"
|
||||
class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#8B5CF6]/20 text-[#E5E7EB] py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<i class="fas fa-cogs mr-1.5 text-[10px]"></i>
|
||||
<span>Backend Gallery</span>
|
||||
</a>
|
||||
|
||||
{{ if not .DisableRuntimeSettings }}
|
||||
<a href="/settings"
|
||||
class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<i class="fas fa-cog mr-1.5 text-[10px]"></i>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if not .DisableRuntimeSettings }}
|
||||
<a href="/settings" class="btn-secondary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-cog mr-1.5 text-[10px]"></i>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Models Section -->
|
||||
@@ -82,41 +79,41 @@
|
||||
|
||||
{{ if eq (len .ModelsConfig) 0 }}
|
||||
<!-- No Models State -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-lg p-8">
|
||||
<div class="card p-8">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-yellow-500/10 border border-yellow-500/20 mb-4">
|
||||
<i class="text-yellow-400 text-xl fas fa-robot"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-[#E5E7EB] mb-2">No models installed yet</h2>
|
||||
<p class="text-sm text-[#94A3B8] mb-6">Get started by installing a model from the gallery or importing it</p>
|
||||
<h2 class="h2 mb-2">No models installed yet</h2>
|
||||
<p class="text-sm text-[var(--color-text-secondary)] mb-6">Get started by installing a model from the gallery or importing it</p>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-2 mb-6">
|
||||
<a href="browse" class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-[#101827] py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<a href="browse" class="btn-primary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-images mr-1.5 text-[10px]"></i>
|
||||
Browse Model Gallery
|
||||
</a>
|
||||
<a href="/import-model" class="inline-flex items-center bg-green-600 hover:bg-green-700 text-white py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<a href="/import-model" class="btn-primary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-upload mr-1.5 text-[10px]"></i>
|
||||
Import Model
|
||||
</a>
|
||||
<a href="https://localai.io/basics/getting_started/" target="_blank" class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-1.5 px-3 rounded text-xs font-medium transition-colors">
|
||||
<a href="https://localai.io/basics/getting_started/" target="_blank" class="btn-secondary text-sm py-1.5 px-3">
|
||||
<i class="fas fa-book mr-1.5 text-[10px]"></i>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{ if ne (len .Models) 0 }}
|
||||
<div class="mt-8 pt-6 border-t border-[#38BDF8]/20">
|
||||
<h3 class="text-lg font-semibold text-[#E5E7EB] mb-2 flex items-center">
|
||||
<i class="fas fa-file-alt mr-2 text-[#38BDF8] text-sm"></i>
|
||||
<div class="mt-8 pt-6 border-t border-[var(--color-primary-border)]/20">
|
||||
<h3 class="text-lg font-semibold text-[var(--color-text-primary)] mb-2 flex items-center">
|
||||
<i class="fas fa-file-alt mr-2 text-[var(--color-primary)] text-sm"></i>
|
||||
Detected Model Files
|
||||
</h3>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">These models were found but don't have configuration files yet</p>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">These models were found but don't have configuration files yet</p>
|
||||
<div class="flex flex-wrap gap-2 justify-center">
|
||||
{{ range .Models }}
|
||||
<div class="bg-[#101827] border border-[#38BDF8]/20 rounded px-2 py-1 flex items-center gap-2">
|
||||
<i class="fas fa-brain text-xs text-[#38BDF8]"></i>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium">{{.}}</span>
|
||||
<div class="bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded px-2 py-1 flex items-center gap-2">
|
||||
<i class="fas fa-brain text-xs text-[var(--color-primary)]"></i>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium">{{.}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
@@ -129,24 +126,24 @@
|
||||
{{ $modelsN := len .ModelsConfig}}
|
||||
{{ $modelsN = add $modelsN (len .Models)}}
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] mb-1 flex items-center">
|
||||
<i class="fas fa-brain mr-2 text-[#38BDF8] text-sm"></i>
|
||||
<h2 class="h3 mb-1 flex items-center">
|
||||
<i class="fas fa-brain mr-2 text-[var(--color-primary)] text-sm"></i>
|
||||
Installed Models
|
||||
</h2>
|
||||
<p class="text-sm text-[#94A3B8] mb-4">
|
||||
<span class="text-[#38BDF8] font-medium">{{$modelsN}}</span> model{{if gt $modelsN 1}}s{{end}} ready to use
|
||||
<p class="text-sm text-[var(--color-text-secondary)] mb-4">
|
||||
<span class="text-[var(--color-primary)] font-medium">{{$modelsN}}</span> model{{if gt $modelsN 1}}s{{end}} ready to use
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto mb-8">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-[#1E293B]">
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Name</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Status</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Backend</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Use Cases</th>
|
||||
<th class="text-right p-2 text-xs font-semibold text-[#94A3B8]">Actions</th>
|
||||
<tr class="border-b border-[var(--color-bg-secondary)]">
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Name</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Status</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Backend</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Use Cases</th>
|
||||
<th class="text-right p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -156,7 +153,7 @@
|
||||
{{ range .ModelsConfig }}
|
||||
{{ $backendCfg := . }}
|
||||
{{ $cfg:= index $galleryConfig .Name}}
|
||||
<tr class="hover:bg-[#1E293B]/50 border-b border-[#1E293B] transition-colors">
|
||||
<tr class="hover:bg-[var(--color-bg-secondary)]/50 border-b border-[var(--color-bg-secondary)] transition-colors">
|
||||
<!-- Name Column -->
|
||||
<td class="p-2">
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -164,15 +161,15 @@
|
||||
{{ if and $cfg $cfg.Icon }}
|
||||
<img src="{{$cfg.Icon}}" class="w-4 h-4 object-contain" alt="{{.Name}} icon">
|
||||
{{ else }}
|
||||
<i class="fas fa-brain text-xs text-[#38BDF8]"></i>
|
||||
<i class="fas fa-brain text-xs text-[var(--color-primary)]"></i>
|
||||
{{ end }}
|
||||
{{ if index $loadedModels .Name }}
|
||||
<div class="absolute -top-0.5 -right-0.5 w-2 h-2 bg-green-500 rounded-full border border-[#1E293B]"></div>
|
||||
<div class="absolute -top-0.5 -right-0.5 w-2 h-2 bg-[var(--color-success)] rounded-full border border-[var(--color-bg-secondary)]"></div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium truncate">{{.Name}}</span>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium truncate">{{.Name}}</span>
|
||||
<a href="/models/edit/{{.Name}}"
|
||||
class="text-[#38BDF8]/60 hover:text-[#38BDF8] hover:bg-[#38BDF8]/10 rounded p-0.5 transition-colors ml-1 flex-shrink-0"
|
||||
class="text-[var(--color-primary)]/60 hover:text-[var(--color-primary)] hover:bg-[var(--color-primary)]/10 rounded p-0.5 transition-colors ml-1 flex-shrink-0"
|
||||
title="Edit {{.Name}}">
|
||||
<i class="fas fa-edit text-[10px]"></i>
|
||||
</a>
|
||||
@@ -183,12 +180,12 @@
|
||||
<td class="p-2">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
{{ if index $loadedModels .Name }}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-green-500/10 text-green-300">
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-success)]/10 text-green-300">
|
||||
<i class="fas fa-circle text-[8px] mr-1"></i>Running
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if and $backendCfg (or (ne $backendCfg.MCP.Servers "") (ne $backendCfg.MCP.Stdio "")) }}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#8B5CF6]/10 text-[#8B5CF6]">
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-accent-light)] text-[var(--color-accent)]">
|
||||
<i class="fas fa-plug text-[8px] mr-1"></i>MCP
|
||||
</span>
|
||||
{{ end }}
|
||||
@@ -198,7 +195,7 @@
|
||||
<!-- Backend Column -->
|
||||
<td class="p-2">
|
||||
{{ if .Backend }}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#38BDF8]/10 text-[#38BDF8]">
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-primary)]/10 text-[var(--color-primary)]">
|
||||
<i class="fas fa-cog text-[8px] mr-1"></i>{{.Backend}}
|
||||
</span>
|
||||
{{ else }}
|
||||
@@ -213,17 +210,17 @@
|
||||
<div class="flex flex-wrap gap-1">
|
||||
{{ range .KnownUsecaseStrings }}
|
||||
{{ if eq . "FLAG_CHAT" }}
|
||||
<a href="chat/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#38BDF8]/10 text-[#38BDF8] hover:bg-[#38BDF8]/20 transition-colors" title="Chat">
|
||||
<a href="chat/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-primary)]/10 text-[var(--color-primary)] hover:bg-[var(--color-primary)]/20 transition-colors" title="Chat">
|
||||
<i class="fas fa-comment-alt text-[8px] mr-1"></i>Chat
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if eq . "FLAG_IMAGE" }}
|
||||
<a href="text2image/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-green-500/10 text-green-300 hover:bg-green-500/20 transition-colors" title="Image">
|
||||
<a href="text2image/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-success)]/10 text-green-300 hover:bg-[var(--color-success)]/20 transition-colors" title="Image">
|
||||
<i class="fas fa-image text-[8px] mr-1"></i>Image
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if eq . "FLAG_TTS" }}
|
||||
<a href="tts/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#8B5CF6]/10 text-[#8B5CF6] hover:bg-[#8B5CF6]/20 transition-colors" title="TTS">
|
||||
<a href="tts/{{$backendCfg.Name}}" class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-accent-light)] text-[var(--color-accent)] hover:bg-[var(--color-accent-light)] transition-colors" title="TTS">
|
||||
<i class="fas fa-microphone text-[8px] mr-1"></i>TTS
|
||||
</a>
|
||||
{{ end }}
|
||||
@@ -253,11 +250,11 @@
|
||||
|
||||
<!-- Models without config -->
|
||||
{{ range .Models }}
|
||||
<tr class="hover:bg-[#1E293B]/50 border-b border-[#1E293B] transition-colors">
|
||||
<tr class="hover:bg-[var(--color-bg-secondary)]/50 border-b border-[var(--color-bg-secondary)] transition-colors">
|
||||
<td class="p-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fas fa-brain text-xs text-[#94A3B8]"></i>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium truncate">{{.}}</span>
|
||||
<i class="fas fa-brain text-xs text-[var(--color-text-secondary)]"></i>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium truncate">{{.}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
@@ -271,10 +268,10 @@
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<span class="text-xs text-[#94A3B8]">—</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">—</span>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<span class="text-xs text-[#94A3B8]">—</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">—</span>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
@@ -288,42 +285,42 @@
|
||||
<div class="mt-8">
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] flex items-center">
|
||||
<i class="fas fa-cogs mr-2 text-[#8B5CF6] text-sm"></i>
|
||||
<h2 class="h3 flex items-center">
|
||||
<i class="fas fa-cogs mr-2 text-[var(--color-accent)] text-sm"></i>
|
||||
Installed Backends
|
||||
</h2>
|
||||
{{ if gt (len .InstalledBackends) 0 }}
|
||||
<button
|
||||
@click="reinstallAllBackends()"
|
||||
:disabled="reinstallingAll"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/80 disabled:opacity-50 disabled:cursor-not-allowed text-white py-1.5 px-3 rounded text-xs font-medium transition-colors"
|
||||
class="btn-primary text-sm py-1.5 px-3"
|
||||
title="Reinstall all backends">
|
||||
<i class="fas fa-arrow-rotate-right mr-1.5 text-[10px]" :class="reinstallingAll ? 'fa-spin' : ''"></i>
|
||||
<span x-text="reinstallingAll ? 'Reinstalling...' : 'Reinstall All'"></span>
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
<p class="text-sm text-[#94A3B8] mb-4">
|
||||
<span class="text-[#8B5CF6] font-medium">{{len .InstalledBackends}}</span> backend{{if gt (len .InstalledBackends) 1}}s{{end}} ready to use
|
||||
<p class="text-sm text-[var(--color-text-secondary)] mb-4">
|
||||
<span class="text-[var(--color-accent)] font-medium">{{len .InstalledBackends}}</span> backend{{if gt (len .InstalledBackends) 1}}s{{end}} ready to use
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{ if eq (len .InstalledBackends) 0 }}
|
||||
<!-- No backends state -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-lg p-8">
|
||||
<div class="card p-8">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-[#8B5CF6]/10 border border-[#8B5CF6]/20 mb-4">
|
||||
<i class="text-[#8B5CF6] text-xl fas fa-cogs"></i>
|
||||
<div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-[var(--color-accent-light)] border border-[var(--color-accent-border)] mb-4">
|
||||
<i class="text-[var(--color-accent)] text-xl fas fa-cogs"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-[#E5E7EB] mb-2">No backends installed yet</h2>
|
||||
<p class="text-sm text-[#94A3B8] mb-6">Backends power your AI models. Install them from the backend gallery to get started</p>
|
||||
<h2 class="h2 mb-2">No backends installed yet</h2>
|
||||
<p class="text-sm text-[var(--color-text-secondary)] mb-6">Backends power your AI models. Install them from the backend gallery to get started</p>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-3">
|
||||
<a href="/browse/backends" class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white py-2 px-4 rounded-lg text-sm font-medium transition-colors">
|
||||
<a href="/browse/backends" class="btn-primary">
|
||||
<i class="fas fa-cogs mr-2 text-xs"></i>
|
||||
Browse Backend Gallery
|
||||
</a>
|
||||
<a href="https://localai.io/backends/" target="_blank" class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#8B5CF6]/20 text-[#E5E7EB] py-2 px-4 rounded-lg text-sm font-medium transition-colors">
|
||||
<a href="https://localai.io/backends/" target="_blank" class="btn-secondary">
|
||||
<i class="fas fa-book mr-2 text-xs"></i>
|
||||
Documentation
|
||||
</a>
|
||||
@@ -335,21 +332,21 @@
|
||||
<div class="overflow-x-auto mb-8">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-[#1E293B]">
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Name</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Type</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[#94A3B8]">Metadata</th>
|
||||
<th class="text-right p-2 text-xs font-semibold text-[#94A3B8]">Actions</th>
|
||||
<tr class="border-b border-[var(--color-bg-secondary)]">
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Name</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Type</th>
|
||||
<th class="text-left p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Metadata</th>
|
||||
<th class="text-right p-2 text-xs font-semibold text-[var(--color-text-secondary)]">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .InstalledBackends }}
|
||||
<tr class="hover:bg-[#1E293B]/50 border-b border-[#1E293B] transition-colors" data-backend-name="{{.Name}}" data-is-system="{{.IsSystem}}">
|
||||
<tr class="hover:bg-[var(--color-bg-secondary)]/50 border-b border-[var(--color-bg-secondary)] transition-colors" data-backend-name="{{.Name}}" data-is-system="{{.IsSystem}}">
|
||||
<!-- Name Column -->
|
||||
<td class="p-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fas fa-cog text-xs text-[#8B5CF6]"></i>
|
||||
<span class="text-xs text-[#E5E7EB] font-medium truncate">{{.Name}}</span>
|
||||
<i class="fas fa-cog text-xs text-[var(--color-accent)]"></i>
|
||||
<span class="text-xs text-[var(--color-text-primary)] font-medium truncate">{{.Name}}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -361,12 +358,12 @@
|
||||
<i class="fas fa-shield-alt text-[8px] mr-1"></i>System
|
||||
</span>
|
||||
{{ else }}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-green-500/10 text-green-300">
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-success)]/10 text-green-300">
|
||||
<i class="fas fa-download text-[8px] mr-1"></i>User
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if .IsMeta }}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#8B5CF6]/10 text-[#8B5CF6]">
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-accent-light)] text-[var(--color-accent)]">
|
||||
<i class="fas fa-layer-group text-[8px] mr-1"></i>Meta
|
||||
</span>
|
||||
{{ end }}
|
||||
@@ -377,17 +374,17 @@
|
||||
<td class="p-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
{{ if and .Metadata .Metadata.Alias }}
|
||||
<span class="text-xs text-[#94A3B8]">
|
||||
<i class="fas fa-tag text-[8px] mr-1"></i>Alias: <span class="text-[#E5E7EB]">{{.Metadata.Alias}}</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">
|
||||
<i class="fas fa-tag text-[8px] mr-1"></i>Alias: <span class="text-[var(--color-text-primary)]">{{.Metadata.Alias}}</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if and .Metadata .Metadata.MetaBackendFor }}
|
||||
<span class="text-xs text-[#94A3B8]">
|
||||
<i class="fas fa-link text-[8px] mr-1"></i>For: <span class="text-[#8B5CF6]">{{.Metadata.MetaBackendFor}}</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">
|
||||
<i class="fas fa-link text-[8px] mr-1"></i>For: <span class="text-[var(--color-accent)]">{{.Metadata.MetaBackendFor}}</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if and .Metadata .Metadata.InstalledAt }}
|
||||
<span class="text-xs text-[#94A3B8]">
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">
|
||||
<i class="fas fa-calendar text-[8px] mr-1"></i>{{.Metadata.InstalledAt}}
|
||||
</span>
|
||||
{{ end }}
|
||||
@@ -401,7 +398,7 @@
|
||||
<button
|
||||
@click="reinstallBackend('{{.Name}}')"
|
||||
:disabled="reinstallingBackends['{{.Name}}']"
|
||||
class="text-[#38BDF8]/60 hover:text-[#38BDF8] hover:bg-[#38BDF8]/10 disabled:opacity-50 disabled:cursor-not-allowed rounded p-1 transition-colors"
|
||||
class="text-[var(--color-primary)]/60 hover:text-[var(--color-primary)] hover:bg-[var(--color-primary)]/10 disabled:opacity-50 disabled:cursor-not-allowed rounded p-1 transition-colors"
|
||||
title="Reinstall {{.Name}}">
|
||||
<i class="fas fa-arrow-rotate-right text-xs" :class="reinstallingBackends['{{.Name}}'] ? 'fa-spin' : ''"></i>
|
||||
</button>
|
||||
@@ -412,7 +409,7 @@
|
||||
<i class="fas fa-trash-alt text-xs"></i>
|
||||
</button>
|
||||
{{ else }}
|
||||
<span class="text-xs text-[#94A3B8]">—</span>
|
||||
<span class="text-xs text-[var(--color-text-secondary)]">—</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -10,22 +10,19 @@
|
||||
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
<!-- Hero Header -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8 mb-8">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
|
||||
<div class="mb-4 md:mb-0">
|
||||
<h1 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-2">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-violet-400 via-purple-400 to-fuchsia-400">
|
||||
{{if .ModelName}}Edit Model: {{.ModelName}}{{else}}Import New Model{{end}}
|
||||
</span>
|
||||
<div>
|
||||
<h1 class="hero-title">
|
||||
{{if .ModelName}}Edit Model: {{.ModelName}}{{else}}Import New Model{{end}}
|
||||
</h1>
|
||||
<p class="text-lg text-[#94A3B8] font-light" x-text="isAdvancedMode ? 'Configure your model settings using YAML' : 'Import a model from URI with preferences'"></p>
|
||||
<p class="hero-subtitle" x-text="isAdvancedMode ? 'Configure your model settings using YAML' : 'Import a model from URI with preferences'"></p>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<!-- Mode Toggle (only show when not in edit mode) -->
|
||||
<template x-if="!isEditMode">
|
||||
<button @click="toggleMode()"
|
||||
class="inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#8B5CF6]/20 text-[#E5E7EB] py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<button @click="toggleMode()" class="btn-secondary">
|
||||
<i class="fas" :class="isAdvancedMode ? 'fa-magic mr-2' : 'fa-code mr-2'"></i>
|
||||
<span x-text="isAdvancedMode ? 'Simple Mode' : 'Advanced Mode'"></span>
|
||||
</button>
|
||||
@@ -33,11 +30,11 @@
|
||||
<!-- Advanced Mode Buttons -->
|
||||
<template x-if="isAdvancedMode">
|
||||
<div class="flex gap-3">
|
||||
<button id="validateBtn" class="inline-flex items-center bg-blue-600 hover:bg-blue-700 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<button id="validateBtn" class="btn-primary">
|
||||
<i class="fas fa-check mr-2"></i>
|
||||
<span>Validate</span>
|
||||
</button>
|
||||
<button id="saveBtn" class="inline-flex items-center bg-green-600 hover:bg-green-700 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
<button id="saveBtn" class="btn-primary">
|
||||
<i class="fas fa-save mr-2"></i>
|
||||
<span>{{if .ModelName}}Update{{else}}Create{{end}}</span>
|
||||
</button>
|
||||
@@ -47,8 +44,7 @@
|
||||
<template x-if="!isAdvancedMode && !isEditMode">
|
||||
<button @click="submitImport()"
|
||||
:disabled="isSubmitting || !importUri.trim()"
|
||||
:class="(isSubmitting || !importUri.trim()) ? 'opacity-50 cursor-not-allowed' : ''"
|
||||
class="inline-flex items-center bg-green-600 hover:bg-green-700 text-white py-3 px-6 rounded-lg font-semibold transition-colors">
|
||||
class="btn-primary">
|
||||
<i class="fas" :class="isSubmitting ? 'fa-spinner fa-spin mr-2' : 'fa-upload mr-2'"></i>
|
||||
<span x-text="isSubmitting ? 'Importing...' : 'Import Model'"></span>
|
||||
</button>
|
||||
@@ -66,7 +62,7 @@
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8">
|
||||
class="card p-8">
|
||||
<div class="space-y-6">
|
||||
<h2 class="text-2xl font-semibold text-[#E5E7EB] flex items-center gap-3 mb-6">
|
||||
<div class="w-10 h-10 rounded-lg bg-green-500/10 flex items-center justify-center">
|
||||
@@ -102,7 +98,7 @@
|
||||
x-model="importUri"
|
||||
type="text"
|
||||
placeholder="huggingface://TheBloke/Llama-2-7B-Chat-GGUF or https://example.com/model.gguf"
|
||||
class="w-full px-4 py-3 bg-[#101827] border border-[#1E293B] rounded-lg text-[#E5E7EB] focus:border-green-500 focus:ring-2 focus:ring-green-500/50 focus:outline-none transition-colors"
|
||||
class="input w-full"
|
||||
:disabled="isSubmitting">
|
||||
<p class="mt-2 text-xs text-[#94A3B8]">
|
||||
Enter the URI or path to the model file you want to import
|
||||
@@ -331,7 +327,7 @@
|
||||
x-model="commonPreferences.description"
|
||||
rows="3"
|
||||
placeholder="Leave empty to use default description"
|
||||
class="w-full px-4 py-2 bg-gray-900/90 border border-gray-700/70 rounded-lg text-gray-200 focus:border-green-500 focus:ring-2 focus:ring-green-500/50 focus:outline-none transition-all resize-none"
|
||||
class="input w-full resize-none"
|
||||
:disabled="isSubmitting"></textarea>
|
||||
<p class="mt-1 text-xs text-gray-400">
|
||||
Custom description for the model. If empty, a default description will be generated.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
{{template "views/partials/head" .}}
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen" x-data="modelsGallery()">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
@@ -17,7 +17,7 @@
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
:class="notification.type === 'error' ? 'bg-red-500' : 'bg-green-500'"
|
||||
:class="notification.type === 'error' ? 'bg-[var(--color-error)]' : 'bg-[var(--color-success)]'"
|
||||
class="rounded-lg p-4 text-white flex items-start space-x-3">
|
||||
<div class="flex-shrink-0">
|
||||
<i :class="notification.type === 'error' ? 'fas fa-exclamation-circle' : 'fas fa-check-circle'" class="text-xl"></i>
|
||||
@@ -35,34 +35,31 @@
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
|
||||
<!-- Hero Header -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-12">
|
||||
<div class="max-w-5xl mx-auto text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] via-[#8B5CF6] to-[#38BDF8]">
|
||||
Model Gallery
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
Model Gallery
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-[#94A3B8] mb-6 font-light">
|
||||
<p class="hero-subtitle">
|
||||
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-[#101827] rounded-lg px-4 py-2">
|
||||
<div class="w-2 h-2 bg-indigo-400 rounded-full mr-2"></div>
|
||||
<div class="flex items-center bg-[var(--color-bg-primary)] rounded-lg px-4 py-2">
|
||||
<div class="w-2 h-2 bg-[var(--color-primary)] rounded-full mr-2"></div>
|
||||
<span class="font-semibold text-indigo-300" x-text="availableModels"></span>
|
||||
<span class="text-[#94A3B8] ml-1">models available</span>
|
||||
<span class="text-[var(--color-text-secondary)] ml-1">models available</span>
|
||||
</div>
|
||||
<a href="/manage" class="flex items-center bg-[#101827] hover:bg-[#1E293B] rounded-lg px-4 py-2 transition-colors border border-[#38BDF8]/30 hover:border-[#38BDF8]/50">
|
||||
<div class="w-2 h-2 bg-emerald-400 rounded-full mr-2"></div>
|
||||
<span class="font-semibold text-emerald-300" x-text="installedModels"></span>
|
||||
<span class="text-[#94A3B8] ml-1">installed</span>
|
||||
<a href="/manage" class="flex items-center bg-[var(--color-bg-primary)] hover:bg-[var(--color-bg-secondary)] rounded-lg px-4 py-2 transition-colors border border-[var(--color-primary-border)]/30 hover:border-[var(--color-primary-border)]/50">
|
||||
<div class="w-2 h-2 bg-[var(--color-success)] rounded-full mr-2"></div>
|
||||
<span class="font-semibold text-[var(--color-success)]" x-text="installedModels"></span>
|
||||
<span class="text-[var(--color-text-secondary)] ml-1">installed</span>
|
||||
</a>
|
||||
<div class="flex items-center bg-[#101827] rounded-lg px-4 py-2">
|
||||
<div class="w-2 h-2 bg-purple-400 rounded-full mr-2"></div>
|
||||
<div class="flex items-center bg-[var(--color-bg-primary)] rounded-lg px-4 py-2">
|
||||
<div class="w-2 h-2 bg-[var(--color-accent)] rounded-full mr-2"></div>
|
||||
<span class="font-semibold text-purple-300" x-text="repositories.length"></span>
|
||||
<span class="text-[#94A3B8] ml-1">repositories</span>
|
||||
<span class="text-[var(--color-text-secondary)] ml-1">repositories</span>
|
||||
</div>
|
||||
<a href="https://localai.io/models/" target="_blank"
|
||||
class="inline-flex items-center bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
<a href="https://localai.io/models/" target="_blank" class="btn-primary">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
<span>Documentation</span>
|
||||
<i class="fas fa-external-link-alt ml-2 text-xs"></i>
|
||||
@@ -74,26 +71,26 @@
|
||||
{{template "views/partials/inprogress" .}}
|
||||
|
||||
<!-- Search and Filter Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-8">
|
||||
<div class="card p-8 mb-8">
|
||||
<div>
|
||||
<!-- Search Input -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-search mr-3 text-[#38BDF8]"></i>
|
||||
<h3 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-search mr-3 text-[var(--color-primary)]"></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-[#94A3B8]"></i>
|
||||
<i class="fas fa-search text-[var(--color-text-secondary)]"></i>
|
||||
</div>
|
||||
<input
|
||||
x-model="searchTerm"
|
||||
@input.debounce.500ms="fetchModels()"
|
||||
class="w-full pl-12 pr-16 py-4 text-base font-normal text-[#E5E7EB] bg-[#101827] border border-[#1E293B] rounded-lg transition-colors focus:text-[#E5E7EB] focus:bg-[#101827] focus:border-[#38BDF8] focus:ring-2 focus:ring-[#38BDF8]/50 focus:outline-none"
|
||||
class="input w-full pl-12 pr-16 py-4"
|
||||
type="search"
|
||||
placeholder="Search models by name, tag, or description...">
|
||||
<span class="absolute right-4 top-4" x-show="loading">
|
||||
<svg class="animate-spin h-6 w-6 text-[#38BDF8]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<svg class="animate-spin h-6 w-6 text-[var(--color-primary)]" 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>
|
||||
@@ -103,48 +100,48 @@
|
||||
|
||||
<!-- Filter by Type -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-lg font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-filter mr-3 text-[#8B5CF6]"></i>
|
||||
<h3 class="text-lg font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-filter mr-3 text-[var(--color-accent)]"></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 @click="filterByTerm('tts')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-primary-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-primary-border)] transition-colors">
|
||||
<i class="fas fa-microphone mr-2"></i>
|
||||
<span>TTS</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('stablediffusion')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-purple-600/20 hover:bg-purple-600/30 text-purple-300 border border-purple-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-accent-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-accent-border)] transition-colors">
|
||||
<i class="fas fa-image mr-2"></i>
|
||||
<span>Image</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('llm')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-blue-600/20 hover:bg-blue-600/30 text-blue-300 border border-blue-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-primary-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-primary-border)] transition-colors">
|
||||
<i class="fas fa-comment-alt mr-2"></i>
|
||||
<span>LLM</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('multimodal')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-green-600/20 hover:bg-green-600/30 text-green-300 border border-green-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-secondary-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-secondary-light)] transition-colors">
|
||||
<i class="fas fa-object-group mr-2"></i>
|
||||
<span>Multimodal</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('embedding')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-cyan-600/20 hover:bg-cyan-600/30 text-cyan-300 border border-cyan-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-primary-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-primary-border)] transition-colors">
|
||||
<i class="fas fa-vector-square mr-2"></i>
|
||||
<span>Embedding</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('rerank')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-amber-600/20 hover:bg-amber-600/30 text-amber-300 border border-amber-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-warning-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-warning-light)] transition-colors">
|
||||
<i class="fas fa-sort-amount-up mr-2"></i>
|
||||
<span>Rerank</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('whisper')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-teal-600/20 hover:bg-teal-600/30 text-teal-300 border border-teal-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-bg-secondary)] hover:bg-[var(--color-secondary-light)] text-[var(--color-text-primary)] border border-[var(--color-border-subtle)] hover:border-[var(--color-secondary-light)] transition-colors">
|
||||
<i class="fas fa-headphones mr-2"></i>
|
||||
<span>Whisper</span>
|
||||
</button>
|
||||
<button @click="filterByTerm('object-detection')"
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-red-600/20 hover:bg-red-600/30 text-red-300 border border-red-500/30 transition-colors">
|
||||
class="flex items-center justify-center rounded-lg px-4 py-3 text-sm font-semibold bg-[var(--color-error)]/20 hover:bg-[var(--color-error)]/30 text-[var(--color-error)] border border-[var(--color-error-light)] transition-colors">
|
||||
<i class="fas fa-eye mr-2"></i>
|
||||
<span>Vision</span>
|
||||
</button>
|
||||
@@ -153,15 +150,15 @@
|
||||
|
||||
<!-- Filter by Tags -->
|
||||
<div x-show="allTags.length > 0">
|
||||
<h3 class="text-lg font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-tags mr-3 text-[#8B5CF6]"></i>
|
||||
<h3 class="text-lg font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-tags mr-3 text-[var(--color-accent)]"></i>
|
||||
Browse by Tags
|
||||
</h3>
|
||||
<div class="max-h-32 overflow-y-auto pr-2">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<template x-for="tag in allTags" :key="tag">
|
||||
<button @click="filterByTerm(tag)"
|
||||
class="inline-flex items-center text-xs px-3 py-2 rounded bg-[#101827] hover:bg-[#101827]/80 text-[#94A3B8] hover:text-[#E5E7EB] border border-[#1E293B] transition-colors">
|
||||
class="inline-flex items-center text-xs px-3 py-2 rounded bg-[var(--color-bg-primary)] hover:bg-[var(--color-bg-primary)]/80 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] border border-[var(--color-bg-secondary)] transition-colors">
|
||||
<i class="fas fa-tag text-xs mr-2"></i>
|
||||
<span x-text="tag"></span>
|
||||
</button>
|
||||
@@ -175,54 +172,54 @@
|
||||
<!-- Results Section -->
|
||||
<div id="search-results" class="transition-all duration-300">
|
||||
<div x-show="loading && models.length === 0" class="text-center py-12">
|
||||
<svg class="animate-spin h-12 w-12 text-blue-500 mx-auto mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<svg class="animate-spin h-12 w-12 text-[var(--color-primary)] mx-auto mb-4" 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>
|
||||
<p class="text-gray-400">Loading models...</p>
|
||||
<p class="text-[var(--color-text-secondary)]">Loading models...</p>
|
||||
</div>
|
||||
|
||||
<div x-show="!loading && models.length === 0" class="text-center py-12">
|
||||
<i class="fas fa-search text-gray-500 text-4xl mb-4"></i>
|
||||
<p class="text-gray-400">No models found matching your criteria</p>
|
||||
<i class="fas fa-search text-[var(--color-text-muted)] text-4xl mb-4"></i>
|
||||
<p class="text-[var(--color-text-secondary)]">No models found matching your criteria</p>
|
||||
</div>
|
||||
|
||||
<!-- Table View -->
|
||||
<div x-show="models.length > 0" class="bg-[#1E293B] rounded-2xl border border-[#38BDF8]/20 overflow-hidden shadow-xl backdrop-blur-sm">
|
||||
<div x-show="models.length > 0" class="card overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="bg-gradient-to-r from-[#38BDF8]/20 to-[#8B5CF6]/20 border-b border-[#38BDF8]/30">
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Icon</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Model Name</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Description</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Repository</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">License</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-4 text-right text-xs font-semibold text-[#E5E7EB] uppercase tracking-wider">Actions</th>
|
||||
<tr class="bg-gradient-to-r from-[#38BDF8]/20 to-[#8B5CF6]/20 border-b border-[var(--color-primary-border)]/30">
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Icon</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Model Name</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Description</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Repository</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">License</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-4 text-right text-xs font-semibold text-[var(--color-text-primary)] uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-[#38BDF8]/20">
|
||||
<template x-for="model in models" :key="model.id">
|
||||
<tr class="hover:bg-[#38BDF8]/10 transition-colors duration-200">
|
||||
<tr class="hover:bg-[var(--color-primary)]/10 transition-colors duration-200">
|
||||
<!-- Icon -->
|
||||
<td class="px-6 py-4">
|
||||
<div class="w-12 h-12 rounded-lg border border-[#38BDF8]/30 flex items-center justify-center bg-[#101827]">
|
||||
<div class="w-12 h-12 rounded-lg border border-[var(--color-primary-border)]/30 flex items-center justify-center bg-[var(--color-bg-primary)]">
|
||||
<img x-show="model.icon"
|
||||
:src="model.icon"
|
||||
class="w-full h-full object-cover rounded-lg"
|
||||
loading="lazy"
|
||||
:alt="model.name">
|
||||
<i x-show="!model.icon" class="fas fa-brain text-xl text-[#38BDF8]"></i>
|
||||
<i x-show="!model.icon" class="fas fa-brain text-xl text-[var(--color-primary)]"></i>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Model Name -->
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-semibold text-[#E5E7EB]" x-text="model.name"></span>
|
||||
<span class="text-sm font-semibold text-[var(--color-text-primary)]" x-text="model.name"></span>
|
||||
<div x-show="model.trustRemoteCode" class="mt-1">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-red-500/20 text-red-300 border border-red-500/30">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-[var(--color-error)]/20 text-[var(--color-error)] border border-[var(--color-error-light)]">
|
||||
<i class="fa-solid fa-circle-exclamation mr-1"></i>
|
||||
Trust Remote Code
|
||||
</span>
|
||||
@@ -232,12 +229,12 @@
|
||||
|
||||
<!-- Description -->
|
||||
<td class="px-6 py-4">
|
||||
<div class="text-sm text-[#94A3B8] max-w-xs truncate" x-text="model.description" :title="model.description"></div>
|
||||
<div class="text-sm text-[var(--color-text-secondary)] max-w-xs truncate" x-text="model.description" :title="model.description"></div>
|
||||
</td>
|
||||
|
||||
<!-- Repository -->
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-[#38BDF8]/10 text-[#E5E7EB] border border-[#38BDF8]/30">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-[var(--color-primary)]/10 text-[var(--color-text-primary)] border border-[var(--color-primary-border)]/30">
|
||||
<i class="fa-brands fa-git-alt mr-1"></i>
|
||||
<span x-text="model.gallery"></span>
|
||||
</span>
|
||||
@@ -245,21 +242,21 @@
|
||||
|
||||
<!-- License -->
|
||||
<td class="px-6 py-4">
|
||||
<span x-show="model.license" class="inline-flex items-center text-xs px-2 py-1 rounded bg-[#8B5CF6]/10 text-[#E5E7EB] border border-[#8B5CF6]/30">
|
||||
<span x-show="model.license" class="inline-flex items-center text-xs px-2 py-1 rounded bg-[var(--color-accent)]/10 text-[var(--color-text-primary)] border border-[var(--color-accent-border)]/30">
|
||||
<i class="fas fa-book mr-1"></i>
|
||||
<span x-text="model.license"></span>
|
||||
</span>
|
||||
<span x-show="!model.license" class="text-xs text-[#94A3B8]">-</span>
|
||||
<span x-show="!model.license" class="text-xs text-[var(--color-text-secondary)]">-</span>
|
||||
</td>
|
||||
|
||||
<!-- Status -->
|
||||
<td class="px-6 py-4">
|
||||
<!-- Processing State -->
|
||||
<div x-show="model.processing" class="min-w-[200px]">
|
||||
<div class="text-xs font-medium text-[#E5E7EB] mb-1">
|
||||
<div class="text-xs font-medium text-[var(--color-text-primary)] mb-1">
|
||||
<span x-text="model.isDeletion ? 'Deleting...' : 'Installing...'"></span>
|
||||
</div>
|
||||
<div x-show="(jobProgress[model.jobID] || 0) === 0" class="text-xs text-[#38BDF8]">
|
||||
<div x-show="(jobProgress[model.jobID] || 0) === 0" class="text-xs text-[var(--color-primary)]">
|
||||
<i class="fas fa-clock mr-1"></i>Queued
|
||||
</div>
|
||||
<div class="progress-table mt-1">
|
||||
@@ -269,7 +266,7 @@
|
||||
|
||||
<!-- Installed State -->
|
||||
<div x-show="!model.processing && model.installed">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-green-500/20 text-green-300 border border-green-500/30">
|
||||
<span class="badge badge-success">
|
||||
<i class="fas fa-check-circle mr-1"></i>
|
||||
Installed
|
||||
</span>
|
||||
@@ -277,7 +274,7 @@
|
||||
|
||||
<!-- Not Installed State -->
|
||||
<div x-show="!model.processing && !model.installed">
|
||||
<span class="inline-flex items-center text-xs px-2 py-1 rounded bg-[#1E293B] text-[#94A3B8] border border-[#38BDF8]/30">
|
||||
<span class="badge">
|
||||
<i class="fas fa-circle mr-1"></i>
|
||||
Not Installed
|
||||
</span>
|
||||
@@ -289,7 +286,7 @@
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<!-- Info Button -->
|
||||
<button @click="openModal(model)"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[#1E293B] hover:bg-[#38BDF8]/20 text-xs font-medium text-[#E5E7EB] transition duration-200 border border-[#38BDF8]/30"
|
||||
class="btn-secondary text-xs px-3 py-1.5"
|
||||
title="View details">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
</button>
|
||||
@@ -298,12 +295,12 @@
|
||||
<template x-if="!model.processing && model.installed">
|
||||
<div class="flex gap-2">
|
||||
<button @click="reinstallModel(model.id)"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[#38BDF8] hover:bg-[#38BDF8]/80 text-xs font-medium text-white transition duration-200"
|
||||
class="btn-primary text-xs px-3 py-1.5"
|
||||
title="Reinstall">
|
||||
<i class="fa-solid fa-arrow-rotate-right"></i>
|
||||
</button>
|
||||
<button @click="deleteModel(model.id)"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-red-600 hover:bg-red-700 text-xs font-medium text-white transition duration-200"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[var(--color-error)] hover:bg-[var(--color-error)] text-xs font-medium text-white transition duration-200"
|
||||
title="Delete">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
@@ -314,12 +311,12 @@
|
||||
<template x-if="!model.processing && !model.installed">
|
||||
<div class="flex gap-2">
|
||||
<button @click="getConfig(model.id)"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[#8B5CF6]/20 hover:bg-[#8B5CF6]/40 text-xs font-medium text-[#E5E7EB] transition duration-200 border border-[#8B5CF6]/30"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[var(--color-accent)]/20 hover:bg-[var(--color-accent)]/40 text-xs font-medium text-[var(--color-text-primary)] transition duration-200 border border-[var(--color-accent-border)]/30"
|
||||
title="Get config">
|
||||
<i class="fa-solid fa-file-code"></i>
|
||||
</button>
|
||||
<button @click="installModel(model.id)"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg bg-[#38BDF8] hover:bg-[#38BDF8]/80 text-xs font-medium text-white transition duration-200"
|
||||
class="btn-primary text-xs px-3 py-1.5"
|
||||
title="Install">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</button>
|
||||
@@ -346,7 +343,7 @@
|
||||
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white" x-text="selectedModel?.name"></h3>
|
||||
<button @click="closeModal()"
|
||||
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white">
|
||||
class="text-[var(--color-text-secondary)] bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white">
|
||||
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
||||
</svg>
|
||||
@@ -361,10 +358,10 @@
|
||||
:src="selectedModel?.icon"
|
||||
class="rounded-lg max-h-48 max-w-96 object-cover"
|
||||
loading="lazy">
|
||||
<i x-show="!selectedModel?.icon" class="fas fa-brain text-6xl text-gray-400 dark:text-gray-500"></i>
|
||||
<i x-show="!selectedModel?.icon" class="fas fa-brain text-6xl text-[var(--color-text-secondary)] dark:text-[var(--color-text-muted)]"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-base leading-relaxed text-gray-500 dark:text-gray-400 break-words max-w-full markdown-content" x-html="renderMarkdown(selectedModel?.description)"></div>
|
||||
<div class="text-base leading-relaxed text-[var(--color-text-muted)] dark:text-[var(--color-text-secondary)] break-words max-w-full markdown-content" x-html="renderMarkdown(selectedModel?.description)"></div>
|
||||
<hr>
|
||||
<template x-if="selectedModel?.urls && selectedModel.urls.length > 0">
|
||||
<div>
|
||||
@@ -372,7 +369,7 @@
|
||||
<ul>
|
||||
<template x-for="url in selectedModel.urls" :key="url">
|
||||
<li>
|
||||
<a :href="url" target="_blank" class="text-base leading-relaxed text-gray-500 dark:text-gray-400 hover:text-blue-500">
|
||||
<a :href="url" target="_blank" class="text-base leading-relaxed text-[var(--color-text-muted)] dark:text-[var(--color-text-secondary)] hover:text-[var(--color-primary)]">
|
||||
<i class="fas fa-link pr-2"></i>
|
||||
<span x-text="url"></span>
|
||||
</a>
|
||||
@@ -387,7 +384,7 @@
|
||||
<ul>
|
||||
<template x-for="file in selectedModel.additionalFiles" :key="file">
|
||||
<li class="mb-0">
|
||||
<p class="text-base leading-tight text-gray-500 dark:text-gray-400">
|
||||
<p class="text-base leading-tight text-[var(--color-text-muted)] dark:text-[var(--color-text-secondary)]">
|
||||
<i class="fas fa-file pr-2"></i>
|
||||
<span x-text="file.filename"></span>
|
||||
</p>
|
||||
@@ -414,7 +411,7 @@
|
||||
<!-- Modal Footer -->
|
||||
<div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600">
|
||||
<button @click="closeModal()"
|
||||
class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700">
|
||||
class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-[var(--color-text-secondary)] dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
@@ -429,13 +426,13 @@
|
||||
<button @click="goToPage(currentPage - 1)"
|
||||
:disabled="currentPage <= 1"
|
||||
:class="currentPage <= 1 ? 'opacity-50 cursor-not-allowed' : ''"
|
||||
class="flex items-center justify-center h-12 w-12 bg-[#1E293B] hover:bg-indigo-600 text-[#94A3B8] hover:text-white rounded-lg transition-colors">
|
||||
class="flex items-center justify-center h-12 w-12 bg-[var(--color-bg-secondary)] hover:bg-indigo-600 text-[var(--color-text-secondary)] hover:text-white rounded-lg transition-colors">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<div class="text-gray-300 text-sm font-medium px-4">
|
||||
<span class="text-gray-400">Page</span>
|
||||
<span class="text-[var(--color-text-secondary)]">Page</span>
|
||||
<span class="text-white font-bold text-lg mx-2" x-text="currentPage"></span>
|
||||
<span class="text-gray-400">of</span>
|
||||
<span class="text-[var(--color-text-secondary)]">of</span>
|
||||
<span class="text-white font-bold text-lg mx-2" x-text="totalPages"></span>
|
||||
</div>
|
||||
<button @click="goToPage(currentPage + 1)"
|
||||
|
||||
@@ -12,37 +12,32 @@
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
{{ if eq .P2PToken "" }}
|
||||
<!-- P2P Disabled - Wizard Guide -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-12">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-[#8B5CF6]/10 border border-[#8B5CF6]/20 mb-6">
|
||||
<i class="text-[#8B5CF6] text-2xl fas fa-circle-nodes"></i>
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
P2P Distribution Not Enabled
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h2 class="hero-title">
|
||||
P2P Distribution Not Enabled
|
||||
</h2>
|
||||
<p class="text-xl text-[#94A3B8] mb-8">
|
||||
<p class="hero-subtitle">
|
||||
Enable peer-to-peer distribution to scale your AI workloads across multiple devices. Share instances, shard models, and pool computational resources across your network.
|
||||
</p>
|
||||
|
||||
<!-- Features Preview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-10">
|
||||
<div class="bg-[#101827] border border-[#38BDF8]/20 rounded-lg p-4">
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-network-wired text-[#38BDF8] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Instance Federation</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Load balance across multiple instances</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-lg p-4">
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-purple-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-puzzle-piece text-[#8B5CF6] text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-sm font-semibold text-[#E5E7EB] mb-2">Model Sharding</h3>
|
||||
<p class="text-xs text-[#94A3B8]">Split large models across workers</p>
|
||||
</div>
|
||||
<div class="bg-[#101827] border border-green-500/20 rounded-lg p-4">
|
||||
<div class="card card-animate">
|
||||
<div class="w-10 h-10 bg-green-500/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fas fa-share-alt text-green-400 text-xl"></i>
|
||||
</div>
|
||||
@@ -52,7 +47,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Setup Instructions -->
|
||||
<div class="bg-[#101827] border border-[#8B5CF6]/20 rounded-xl p-6 mb-8 text-left">
|
||||
<div class="card mb-8 text-left">
|
||||
<h3 class="text-lg font-bold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-rocket text-[#8B5CF6] mr-2"></i>
|
||||
How to Enable P2P
|
||||
@@ -118,12 +113,10 @@
|
||||
<div class="animation-container mb-8">
|
||||
<canvas id="networkCanvas"></canvas>
|
||||
<div class="text-overlay">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
<i class="fa-solid fa-circle-nodes mr-2"></i> Distributed AI Computing
|
||||
</span>
|
||||
<h1 class="hero-title">
|
||||
<i class="fa-solid fa-circle-nodes mr-2"></i> Distributed AI Computing
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8]">
|
||||
<p class="hero-subtitle">
|
||||
Scale your AI workloads across multiple devices with peer-to-peer distribution
|
||||
<a href="https://localai.io/features/distribute/" target="_blank" class="text-[#38BDF8] hover:text-[#8B5CF6] transition-colors">
|
||||
<i class="fas fa-circle-info ml-2"></i>
|
||||
@@ -133,14 +126,12 @@
|
||||
</div>
|
||||
|
||||
<!-- How P2P Distribution Works -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8 mb-12">
|
||||
<div class="card p-8 mb-12">
|
||||
<div>
|
||||
<div class="text-center mb-10">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-400">
|
||||
<h2 class="h2 mb-4">
|
||||
How P2P Distribution Works
|
||||
</span>
|
||||
</h2>
|
||||
</h2>
|
||||
<p class="text-lg text-[#94A3B8] max-w-3xl mx-auto">
|
||||
LocalAI leverages cutting-edge peer-to-peer technologies to distribute AI workloads intelligently across your network
|
||||
</p>
|
||||
|
||||
@@ -9,20 +9,28 @@
|
||||
<script defer src="static/assets/alpine.js"></script>
|
||||
<script defer src="static/assets/marked.js"></script>
|
||||
<script defer src="static/assets/purify.js"></script>
|
||||
<!-- LocalAI Design System CSS -->
|
||||
<link href="static/theme.css" rel="stylesheet" />
|
||||
<link href="static/typography.css" rel="stylesheet" />
|
||||
<link href="static/animations.css" rel="stylesheet" />
|
||||
<link href="static/components.css" rel="stylesheet" />
|
||||
<link href="static/general.css" rel="stylesheet" />
|
||||
<link href="static/assets/font1.css" rel="stylesheet">
|
||||
<link href="static/assets/font2.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="static/assets/tw-elements.css" />
|
||||
<script src="static/assets/tailwindcss.js"></script>
|
||||
|
||||
<!-- Preload critical fonts -->
|
||||
<link rel="preload" href="static/assets/playfair-display-bold.ttf" as="font" type="font/ttf" crossorigin>
|
||||
<link rel="preload" href="static/assets/space-grotesk-regular.ttf" as="font" type="font/ttf" crossorigin>
|
||||
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
fontFamily: {
|
||||
sans: ["Roboto", "sans-serif"],
|
||||
body: ["Roboto", "sans-serif"],
|
||||
mono: ["ui-monospace", "monospace"],
|
||||
sans: ["Space Grotesk", "-apple-system", "BlinkMacSystemFont", "sans-serif"],
|
||||
body: ["Space Grotesk", "-apple-system", "BlinkMacSystemFont", "sans-serif"],
|
||||
display: ["Playfair Display", "serif"],
|
||||
mono: ["JetBrains Mono", "Fira Code", "monospace"],
|
||||
},
|
||||
},
|
||||
corePlugins: {
|
||||
@@ -77,114 +85,4 @@
|
||||
<link href="static/assets/fontawesome/css/brands.css" rel="stylesheet" />
|
||||
<link href="static/assets/fontawesome/css/solid.css" rel="stylesheet" />
|
||||
<script src="static/assets/flowbite.min.js"></script>
|
||||
|
||||
<!-- Tech Noir UI Styling -->
|
||||
<style>
|
||||
/* Core Tech Noir Color Palette */
|
||||
:root {
|
||||
--tn-bg: #101827;
|
||||
--tn-ui: #1E293B;
|
||||
--tn-primary: #38BDF8;
|
||||
--tn-secondary: #8B5CF6;
|
||||
--tn-text: #E5E7EB;
|
||||
--tn-muted: #94A3B8;
|
||||
}
|
||||
|
||||
.animation-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 25vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, var(--tn-bg) 0%, var(--tn-ui) 100%);
|
||||
}
|
||||
canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.text-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
.fa-circle-nodes {
|
||||
animation: rotateCircleNodes 8s linear infinite;
|
||||
display: inline-block;
|
||||
filter: drop-shadow(0 0 8px var(--tn-primary));
|
||||
}
|
||||
@keyframes rotateCircleNodes {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
.fa-flask {
|
||||
animation: shakeFlask 3s ease-in-out infinite;
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
@keyframes shakeFlask {
|
||||
0%, 10% { transform: rotate(0deg); }
|
||||
20% { transform: rotate(-10deg); }
|
||||
30% { transform: rotate(10deg); }
|
||||
40% { transform: rotate(-8deg); }
|
||||
50% { transform: rotate(8deg); }
|
||||
60% { transform: rotate(-5deg); }
|
||||
70% { transform: rotate(5deg); }
|
||||
80% { transform: rotate(-2deg); }
|
||||
90% { transform: rotate(2deg); }
|
||||
100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
/* Active node with cyan glow */
|
||||
.active-node {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.active-node::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--tn-primary), transparent);
|
||||
animation: nodeGlow 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes nodeGlow {
|
||||
0% { left: -100%; }
|
||||
50% { left: 100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
/* Enhanced scrollbar styling */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--tn-bg);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--tn-ui);
|
||||
border-radius: 5px;
|
||||
border: 2px solid var(--tn-bg);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--tn-primary);
|
||||
}
|
||||
|
||||
/* Glow effects for interactive elements */
|
||||
.glow-on-hover:hover {
|
||||
box-shadow: 0 0 20px rgba(56, 189, 248, 0.3);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav class="bg-[#101827] shadow-2xl border-b border-[#1E293B]">
|
||||
<nav class="bg-[var(--color-bg-primary)] shadow-2xl border-b border-[var(--color-bg-secondary)]">
|
||||
<div class="container mx-auto px-4 py-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
@@ -6,46 +6,46 @@
|
||||
<a href="./" class="flex items-center group">
|
||||
<img src="static/logo_horizontal.png"
|
||||
alt="LocalAI Logo"
|
||||
class="h-10 mr-3 brightness-110 transition-all duration-300 group-hover:brightness-125 group-hover:drop-shadow-[0_0_8px_rgba(56,189,248,0.5)]">
|
||||
class="h-10 mr-3 brightness-110 transition-all duration-300 group-hover:brightness-125 group-hover:drop-shadow-[0_0_8px_var(--color-primary-border)]">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Menu button for small screens -->
|
||||
<div class="lg:hidden">
|
||||
<button id="menu-toggle" class="text-[#94A3B8] hover:text-[#38BDF8] focus:outline-none p-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B]">
|
||||
<button id="menu-toggle" class="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] focus:outline-none p-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)]">
|
||||
<i class="fas fa-bars fa-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Navigation links -->
|
||||
<div class="hidden lg:flex lg:items-center lg:justify-end lg:space-x-1" x-data="{ manageOpen: false }">
|
||||
<a href="./" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fas fa-home text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Home
|
||||
<a href="./" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fas fa-home text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Home
|
||||
</a>
|
||||
<a href="chat/" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-comments text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Chat
|
||||
<a href="chat/" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-comments text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Chat
|
||||
</a>
|
||||
<a href="text2image/" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fas fa-image text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Images
|
||||
<a href="text2image/" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fas fa-image text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Images
|
||||
</a>
|
||||
<a href="tts/" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-music text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>TTS
|
||||
<a href="tts/" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-music text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>TTS
|
||||
</a>
|
||||
<a href="talk/" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-phone text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Talk
|
||||
<a href="talk/" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fa-solid fa-phone text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Talk
|
||||
</a>
|
||||
<a href="swagger/" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fas fa-code text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>API
|
||||
<a href="swagger/" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fas fa-code text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>API
|
||||
</a>
|
||||
<a href="agent-jobs" class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fas fa-tasks text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Agent Jobs
|
||||
<a href="agent-jobs" class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fas fa-tasks text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Agent Jobs
|
||||
</a>
|
||||
|
||||
<!-- System Dropdown -->
|
||||
<div class="relative" @click.away="manageOpen = false">
|
||||
<button @click="manageOpen = !manageOpen"
|
||||
class="text-[#94A3B8] hover:text-[#E5E7EB] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[#1E293B] flex items-center group text-sm">
|
||||
<i class="fas fa-cog text-[#38BDF8] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Settings
|
||||
class="text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] px-2 py-2 rounded-lg transition duration-300 ease-in-out hover:bg-[var(--color-bg-secondary)] flex items-center group text-sm">
|
||||
<i class="fas fa-cog text-[var(--color-primary)] mr-1.5 text-sm group-hover:scale-110 transition-transform"></i>Settings
|
||||
<i class="fas fa-chevron-down ml-1 text-xs transition-transform" :class="manageOpen ? 'rotate-180' : ''"></i>
|
||||
</button>
|
||||
<div x-show="manageOpen"
|
||||
@@ -55,18 +55,18 @@
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
class="absolute top-full right-0 mt-1 w-48 bg-[#1E293B] border border-[#38BDF8]/20 rounded-lg shadow-lg z-50 py-1">
|
||||
<a href="browse/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#101827] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-brain text-[#38BDF8] mr-2 text-xs"></i>Models
|
||||
class="absolute top-full right-0 mt-1 w-48 bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded-lg shadow-lg z-50 py-1">
|
||||
<a href="browse/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-primary)] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-brain text-[var(--color-primary)] mr-2 text-xs"></i>Models
|
||||
</a>
|
||||
<a href="browse/backends" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#101827] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-server text-[#38BDF8] mr-2 text-xs"></i>Backends
|
||||
<a href="browse/backends" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-primary)] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-server text-[var(--color-primary)] mr-2 text-xs"></i>Backends
|
||||
</a>
|
||||
<a href="p2p/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#101827] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fa-solid fa-circle-nodes text-[#38BDF8] mr-2 text-xs"></i>Swarm
|
||||
<a href="p2p/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-primary)] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fa-solid fa-circle-nodes text-[var(--color-primary)] mr-2 text-xs"></i>Swarm
|
||||
</a>
|
||||
<a href="/manage" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#101827] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-cog text-[#38BDF8] mr-2 text-xs"></i>System
|
||||
<a href="/manage" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-primary)] px-3 py-2 text-sm transition-colors flex items-center">
|
||||
<i class="fas fa-cog text-[var(--color-primary)] mr-2 text-xs"></i>System
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,17 +75,17 @@
|
||||
|
||||
<!-- Collapsible menu for small screens -->
|
||||
<div class="hidden lg:hidden" id="mobile-menu" x-data="{ manageOpen: false }">
|
||||
<div class="pt-3 pb-2 space-y-1 border-t border-[#1E293B] mt-2">
|
||||
<a href="./" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-home text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Home
|
||||
<div class="pt-3 pb-2 space-y-1 border-t border-[var(--color-bg-secondary)] mt-2">
|
||||
<a href="./" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-home text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Home
|
||||
</a>
|
||||
|
||||
<!-- System with submenu -->
|
||||
<div>
|
||||
<button @click="manageOpen = !manageOpen"
|
||||
class="w-full text-left text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center justify-between text-sm">
|
||||
class="w-full text-left text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center justify-between text-sm">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-cog text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Settings
|
||||
<i class="fas fa-cog text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Settings
|
||||
</div>
|
||||
<i class="fas fa-chevron-down text-xs transition-transform" :class="manageOpen ? 'rotate-180' : ''"></i>
|
||||
</button>
|
||||
@@ -97,38 +97,38 @@
|
||||
x-transition:leave-start="opacity-100 max-h-96"
|
||||
x-transition:leave-end="opacity-0 max-h-0"
|
||||
class="overflow-hidden">
|
||||
<a href="browse/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-brain text-[#38BDF8] mr-3 w-5 text-center text-xs"></i>Models
|
||||
<a href="browse/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-brain text-[var(--color-primary)] mr-3 w-5 text-center text-xs"></i>Models
|
||||
</a>
|
||||
<a href="browse/backends" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-server text-[#38BDF8] mr-3 w-5 text-center text-xs"></i>Backends
|
||||
<a href="browse/backends" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-server text-[var(--color-primary)] mr-3 w-5 text-center text-xs"></i>Backends
|
||||
</a>
|
||||
<a href="p2p/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-circle-nodes text-[#38BDF8] mr-3 w-5 text-center text-xs"></i>Swarm
|
||||
<a href="p2p/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-circle-nodes text-[var(--color-primary)] mr-3 w-5 text-center text-xs"></i>Swarm
|
||||
</a>
|
||||
<a href="/manage" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-cog text-[#38BDF8] mr-3 w-5 text-center text-xs"></i>System
|
||||
<a href="/manage" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] pl-8 pr-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-cog text-[var(--color-primary)] mr-3 w-5 text-center text-xs"></i>System
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="chat/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-comments text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Chat
|
||||
<a href="chat/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-comments text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Chat
|
||||
</a>
|
||||
<a href="text2image/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-image text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Images
|
||||
<a href="text2image/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-image text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Images
|
||||
</a>
|
||||
<a href="tts/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-music text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>TTS
|
||||
<a href="tts/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-music text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>TTS
|
||||
</a>
|
||||
<a href="talk/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-phone text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Talk
|
||||
<a href="talk/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fa-solid fa-phone text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Talk
|
||||
</a>
|
||||
<a href="swagger/" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-code text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>API
|
||||
<a href="swagger/" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-code text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>API
|
||||
</a>
|
||||
<a href="agent-jobs" class="block text-[#94A3B8] hover:text-[#E5E7EB] hover:bg-[#1E293B] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-tasks text-[#38BDF8] mr-3 w-5 text-center text-sm"></i>Agent Jobs
|
||||
<a href="agent-jobs" class="block text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] px-3 py-2 rounded-lg transition duration-300 ease-in-out flex items-center text-sm">
|
||||
<i class="fas fa-tasks text-[var(--color-primary)] mr-3 w-5 text-center text-sm"></i>Agent Jobs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
{{template "views/partials/head" .}}
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen" x-data="settingsDashboard()">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
@@ -36,27 +36,27 @@
|
||||
<!-- Header -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h1 class="text-2xl font-semibold text-[#E5E7EB]">
|
||||
<h1 class="h2">
|
||||
Application Settings
|
||||
</h1>
|
||||
<a href="/manage"
|
||||
class="inline-flex items-center text-[#94A3B8] hover:text-[#E5E7EB] transition-colors">
|
||||
class="inline-flex items-center text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors">
|
||||
<i class="fas fa-arrow-left mr-2 text-sm"></i>
|
||||
<span class="text-sm">Back to Manage</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-sm text-[#94A3B8]">Configure watchdog and backend request settings</p>
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">Configure watchdog and backend request settings</p>
|
||||
</div>
|
||||
|
||||
<!-- Settings Form -->
|
||||
<form @submit.prevent="saveSettings()" class="space-y-6">
|
||||
<!-- Watchdog Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-shield-alt mr-2 text-[#38BDF8] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-shield-alt mr-2 text-[var(--color-primary)] text-sm"></i>
|
||||
Watchdog Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure automatic monitoring and management of backend processes
|
||||
</p>
|
||||
|
||||
@@ -64,76 +64,76 @@
|
||||
<!-- Enable Watchdog -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Enable Watchdog</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable automatic monitoring of backend processes</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Enable Watchdog</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable automatic monitoring of backend processes</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.watchdog_enabled"
|
||||
@change="updateWatchdogEnabled()"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#38BDF8]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#38BDF8]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-primary-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-primary)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Enable Idle Check -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Enable Idle Check</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Automatically stop backends that are idle for too long</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Enable Idle Check</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Automatically stop backends that are idle for too long</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.watchdog_idle_enabled"
|
||||
:disabled="!settings.watchdog_enabled"
|
||||
class="sr-only peer" :class="!settings.watchdog_enabled ? 'opacity-50' : ''">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#38BDF8]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#38BDF8]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-primary-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-primary)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Idle Timeout -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Idle Timeout</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Time before an idle backend is stopped (e.g., 15m, 1h)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Idle Timeout</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Time before an idle backend is stopped (e.g., 15m, 1h)</p>
|
||||
<input type="text" x-model="settings.watchdog_idle_timeout"
|
||||
:disabled="!settings.watchdog_idle_enabled"
|
||||
placeholder="15m"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#38BDF8]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#38BDF8]/50"
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary-border)]"
|
||||
:class="!settings.watchdog_idle_enabled ? 'opacity-50 cursor-not-allowed' : ''">
|
||||
</div>
|
||||
|
||||
<!-- Enable Busy Check -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Enable Busy Check</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Automatically stop backends that are busy for too long (stuck processes)</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Enable Busy Check</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Automatically stop backends that are busy for too long (stuck processes)</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.watchdog_busy_enabled"
|
||||
:disabled="!settings.watchdog_enabled"
|
||||
class="sr-only peer" :class="!settings.watchdog_enabled ? 'opacity-50' : ''">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#38BDF8]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#38BDF8]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-primary-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-primary)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Busy Timeout -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Busy Timeout</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Time before a busy backend is stopped (e.g., 5m, 30m)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Busy Timeout</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Time before a busy backend is stopped (e.g., 5m, 30m)</p>
|
||||
<input type="text" x-model="settings.watchdog_busy_timeout"
|
||||
:disabled="!settings.watchdog_busy_enabled"
|
||||
placeholder="5m"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#38BDF8]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#38BDF8]/50"
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-primary-border)]/20 rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary-border)]"
|
||||
:class="!settings.watchdog_busy_enabled ? 'opacity-50 cursor-not-allowed' : ''">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backend Request Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-cogs mr-2 text-[#8B5CF6] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-accent-light)] rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-cogs mr-2 text-[var(--color-accent)] text-sm"></i>
|
||||
Backend Request Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure how backends handle multiple requests
|
||||
</p>
|
||||
|
||||
@@ -141,97 +141,97 @@
|
||||
<!-- Single Backend Mode -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Single Backend Mode</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Allow only one backend to be active at a time</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Single Backend Mode</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Allow only one backend to be active at a time</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.single_backend"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#8B5CF6]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#8B5CF6]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-accent-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-accent)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Parallel Backend Requests -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Parallel Backend Requests</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable backends to handle multiple requests in parallel (if supported)</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Parallel Backend Requests</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable backends to handle multiple requests in parallel (if supported)</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.parallel_backend_requests"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#8B5CF6]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#8B5CF6]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-accent-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-accent)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Performance Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#10B981]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-tachometer-alt mr-2 text-[#10B981] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-success-light)] rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-tachometer-alt mr-2 text-[var(--color-success)] text-sm"></i>
|
||||
Performance Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure default performance parameters for models
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Threads -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Default Threads</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Number of threads to use for model inference (0 = auto)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Default Threads</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Number of threads to use for model inference (0 = auto)</p>
|
||||
<input type="number" x-model="settings.threads"
|
||||
min="0"
|
||||
placeholder="0"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#10B981]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#10B981]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-success-light)] rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-success-light)]">
|
||||
</div>
|
||||
|
||||
<!-- Context Size -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Default Context Size</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Default context window size for models</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Default Context Size</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Default context window size for models</p>
|
||||
<input type="number" x-model="settings.context_size"
|
||||
min="0"
|
||||
placeholder="512"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#10B981]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#10B981]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-success-light)] rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-success-light)]">
|
||||
</div>
|
||||
|
||||
<!-- F16 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">F16 Precision</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Use 16-bit floating point precision</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">F16 Precision</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Use 16-bit floating point precision</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.f16"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#10B981]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#10B981]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-success-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-success)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Debug -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Debug Mode</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable debug logging</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Debug Mode</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable debug logging</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.debug"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#10B981]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#10B981]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-success-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-success)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#F59E0B]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-globe mr-2 text-[#F59E0B] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-warning-light)] rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-globe mr-2 text-[var(--color-warning)] text-sm"></i>
|
||||
API Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure CORS and CSRF protection
|
||||
</p>
|
||||
|
||||
@@ -239,138 +239,138 @@
|
||||
<!-- CORS -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Enable CORS</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable Cross-Origin Resource Sharing</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Enable CORS</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable Cross-Origin Resource Sharing</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.cors"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#F59E0B]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#F59E0B]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-warning-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-warning)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- CORS Allow Origins -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">CORS Allow Origins</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Comma-separated list of allowed origins</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">CORS Allow Origins</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Comma-separated list of allowed origins</p>
|
||||
<input type="text" x-model="settings.cors_allow_origins"
|
||||
placeholder="*"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#F59E0B]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#F59E0B]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-warning-light)] rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-warning-light)]">
|
||||
</div>
|
||||
|
||||
<!-- CSRF -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Enable CSRF Protection</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable Cross-Site Request Forgery protection</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Enable CSRF Protection</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable Cross-Site Request Forgery protection</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.csrf"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#F59E0B]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#F59E0B]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-warning-light)] rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-warning)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- P2P Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#EC4899]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-network-wired mr-2 text-[#EC4899] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-accent)]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-network-wired mr-2 text-[var(--color-accent)] text-sm"></i>
|
||||
P2P Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure peer-to-peer networking
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- P2P Token -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">P2P Token</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Authentication token for P2P network (set to 0 to generate a new token)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">P2P Token</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Authentication token for P2P network (set to 0 to generate a new token)</p>
|
||||
<input type="text" x-model="settings.p2p_token"
|
||||
placeholder=""
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#EC4899]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#EC4899]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-accent)]/20 rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/50">
|
||||
</div>
|
||||
|
||||
<!-- P2P Network ID -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">P2P Network ID</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Network identifier for P2P connections</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">P2P Network ID</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Network identifier for P2P connections</p>
|
||||
<input type="text" x-model="settings.p2p_network_id"
|
||||
placeholder=""
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#EC4899]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#EC4899]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-accent)]/20 rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/50">
|
||||
</div>
|
||||
|
||||
<!-- Federated -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Federated Mode</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Enable federated instance mode</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Federated Mode</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Enable federated instance mode</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.federated"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#EC4899]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#EC4899]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-accent)]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-accent)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Agent Jobs Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#06B6D4]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-tasks mr-2 text-[#06B6D4] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-primary)]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-tasks mr-2 text-[var(--color-primary)] text-sm"></i>
|
||||
Agent Jobs Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure agent job retention and cleanup
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Agent Job Retention Days -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Job Retention Days</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Number of days to keep job history (default: 30)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Job Retention Days</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Number of days to keep job history (default: 30)</p>
|
||||
<input type="number" x-model="settings.agent_job_retention_days"
|
||||
min="0"
|
||||
placeholder="30"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#06B6D4]/20 rounded text-sm text-[#E5E7EB] focus:outline-none focus:ring-2 focus:ring-[#06B6D4]/50">
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-primary)]/20 rounded text-sm text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]/50">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Keys Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#EF4444]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-key mr-2 text-[#EF4444] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-error-light)] rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-key mr-2 text-[var(--color-error)] text-sm"></i>
|
||||
API Keys
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Manage API keys for authentication. Keys from environment variables are always included.
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- API Keys List -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">API Keys</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">List of API keys (one per line or comma-separated)</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">API Keys</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">List of API keys (one per line or comma-separated)</p>
|
||||
<textarea x-model="settings.api_keys_text"
|
||||
rows="4"
|
||||
placeholder="sk-1234567890abcdef sk-0987654321fedcba"
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#EF4444]/20 rounded text-sm text-[#E5E7EB] font-mono focus:outline-none focus:ring-2 focus:ring-[#EF4444]/50"></textarea>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Note: API keys are sensitive. Handle with care.</p>
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-error-light)] rounded text-sm text-[var(--color-text-primary)] font-mono focus:outline-none focus:ring-2 focus:ring-[var(--color-error-light)]"></textarea>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Note: API keys are sensitive. Handle with care.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gallery Settings Section -->
|
||||
<div class="bg-[#1E293B] border border-[#6366F1]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[#E5E7EB] mb-4 flex items-center">
|
||||
<i class="fas fa-images mr-2 text-[#6366F1] text-sm"></i>
|
||||
<div class="bg-[var(--color-bg-secondary)] border border-[var(--color-accent)]/20 rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4 flex items-center">
|
||||
<i class="fas fa-images mr-2 text-[var(--color-accent)] text-sm"></i>
|
||||
Gallery Settings
|
||||
</h2>
|
||||
<p class="text-xs text-[#94A3B8] mb-4">
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-4">
|
||||
Configure model and backend galleries
|
||||
</p>
|
||||
|
||||
@@ -378,47 +378,47 @@
|
||||
<!-- Autoload Galleries -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Autoload Galleries</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Automatically load model galleries on startup</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Autoload Galleries</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Automatically load model galleries on startup</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.autoload_galleries"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#6366F1]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#6366F1]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-accent)]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-accent)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Autoload Backend Galleries -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#E5E7EB]">Autoload Backend Galleries</label>
|
||||
<p class="text-xs text-[#94A3B8] mt-1">Automatically load backend galleries on startup</p>
|
||||
<label class="text-sm font-medium text-[var(--color-text-primary)]">Autoload Backend Galleries</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mt-1">Automatically load backend galleries on startup</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="settings.autoload_backend_galleries"
|
||||
class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-[#101827] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#6366F1]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#6366F1]"></div>
|
||||
<div class="w-11 h-6 bg-[var(--color-bg-primary)] peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--color-accent)]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--color-accent)]"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Galleries (JSON) -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Model Galleries (JSON)</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Array of gallery objects with 'url' and 'name' fields</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Model Galleries (JSON)</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Array of gallery objects with 'url' and 'name' fields</p>
|
||||
<textarea x-model="settings.galleries_json"
|
||||
rows="4"
|
||||
placeholder='[{"url": "https://example.com", "name": "Example Gallery"}]'
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#6366F1]/20 rounded text-sm text-[#E5E7EB] font-mono focus:outline-none focus:ring-2 focus:ring-[#6366F1]/50"></textarea>
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-accent)]/20 rounded text-sm text-[var(--color-text-primary)] font-mono focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/50"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Backend Galleries (JSON) -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[#E5E7EB] mb-2">Backend Galleries (JSON)</label>
|
||||
<p class="text-xs text-[#94A3B8] mb-2">Array of backend gallery objects with 'url' and 'name' fields</p>
|
||||
<label class="block text-sm font-medium text-[var(--color-text-primary)] mb-2">Backend Galleries (JSON)</label>
|
||||
<p class="text-xs text-[var(--color-text-secondary)] mb-2">Array of backend gallery objects with 'url' and 'name' fields</p>
|
||||
<textarea x-model="settings.backend_galleries_json"
|
||||
rows="4"
|
||||
placeholder='[{"url": "https://example.com", "name": "Example Backend Gallery"}]'
|
||||
class="w-full px-3 py-2 bg-[#101827] border border-[#6366F1]/20 rounded text-sm text-[#E5E7EB] font-mono focus:outline-none focus:ring-2 focus:ring-[#6366F1]/50"></textarea>
|
||||
class="w-full px-3 py-2 bg-[var(--color-bg-primary)] border border-[var(--color-accent)]/20 rounded text-sm text-[var(--color-text-primary)] font-mono focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/50"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -441,7 +441,7 @@
|
||||
<div class="flex justify-end">
|
||||
<button type="submit"
|
||||
:disabled="saving"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 disabled:opacity-50 disabled:cursor-not-allowed text-white py-2 px-6 rounded-lg font-medium transition-colors">
|
||||
class="btn-primary">
|
||||
<i class="fas fa-save mr-2" :class="saving ? 'fa-spin fa-spinner' : ''"></i>
|
||||
<span x-text="saving ? 'Saving...' : 'Save Settings'"></span>
|
||||
</button>
|
||||
|
||||
@@ -9,20 +9,18 @@
|
||||
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
<!-- Hero Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-10">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
<i class="fas fa-comments mr-2"></i>Talk Interface
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
<i class="fas fa-comments mr-2"></i>Talk Interface
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8] mb-6">Speak with your AI models using voice interaction</p>
|
||||
<p class="hero-subtitle">Speak with your AI models using voice interaction</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Talk Interface -->
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="bg-[#1E293B] border border-[#1E293B] rounded-xl overflow-hidden">
|
||||
<div class="card overflow-hidden">
|
||||
<!-- Talk Interface Body -->
|
||||
<div class="p-6">
|
||||
<!-- Recording Status -->
|
||||
|
||||
@@ -3,59 +3,45 @@
|
||||
{{template "views/partials/head" .}}
|
||||
<script defer src="static/image.js"></script>
|
||||
|
||||
<body class="bg-[#101827] text-[#E5E7EB]">
|
||||
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
|
||||
<div class="flex flex-col min-h-screen">
|
||||
|
||||
{{template "views/partials/navbar" .}}
|
||||
<div class="container mx-auto px-4 py-8 flex-grow" x-data="{ component: 'menu' }">
|
||||
|
||||
<!-- Hero Section -->
|
||||
<div class="bg-[#1E293B] border border-[#38BDF8]/20 rounded-xl p-8 mb-6">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#38BDF8] to-[#8B5CF6]">
|
||||
Image Generation {{ if .Model }} with {{.Model}} {{ end }}
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
Image Generation {{ if .Model }} with {{.Model}} {{ end }}
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8] mb-6">Create stunning images from text descriptions</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="https://localai.io/features/image-generation/" target="_blank"
|
||||
class="inline-flex items-center bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-[#101827] font-semibold py-2 px-6 rounded-lg transition-colors">
|
||||
<i class="fas fa-book-reader mr-2"></i>
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<a href="browse"
|
||||
class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white font-semibold py-2 px-6 rounded-lg transition-colors">
|
||||
<i class="fas fa-images mr-2"></i>
|
||||
<span>Gallery</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="hero-subtitle">Create stunning images from text descriptions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Model Selection - Positioned between hero and generation form -->
|
||||
<div class="bg-[#1E293B] border border-[#1E293B] rounded-xl p-5 mb-6">
|
||||
<div class="card p-5 mb-6">
|
||||
<div class="flex items-center">
|
||||
<div class="text-lg font-medium text-[#38BDF8] mr-4">
|
||||
<div class="text-lg font-medium text-[var(--color-primary)] mr-4">
|
||||
<i class="fas fa-palette mr-2"></i>Select Model:
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<select x-data="{ link : '' }" x-model="link" x-init="$watch('link', value => window.location = link)"
|
||||
id="model-select"
|
||||
class="bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#38BDF8] focus:ring focus:ring-[#38BDF8] focus:ring-opacity-50 rounded-lg shadow-sm p-2.5 pr-10 appearance-none w-full max-w-md transition-colors duration-200"
|
||||
class="input w-full max-w-md p-2.5 pr-10"
|
||||
>
|
||||
<option value="" disabled class="text-[#94A3B8]">Select a model</option>
|
||||
<option value="" disabled class="text-[var(--color-text-secondary)]">Select a model</option>
|
||||
{{ $model:=.Model}}
|
||||
{{ range .ModelsConfig }}
|
||||
{{ $cfg := . }}
|
||||
{{ range .KnownUsecaseStrings }}
|
||||
{{ if eq . "FLAG_IMAGE" }}
|
||||
<option value="text2image/{{$cfg.Name}}" {{ if eq $cfg.Name $model }} selected {{end}} class="bg-[#101827] text-[#E5E7EB]">{{$cfg.Name}}</option>
|
||||
<option value="text2image/{{$cfg.Name}}" {{ if eq $cfg.Name $model }} selected {{end}} class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">{{$cfg.Name}}</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ range .ModelsWithoutConfig }}
|
||||
<option value="text2image/{{.}}" {{ if eq . $model }} selected {{ end }} class="bg-[#101827] text-[#E5E7EB]">{{.}}</option>
|
||||
<option value="text2image/{{.}}" {{ if eq . $model }} selected {{ end }} class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
@@ -63,15 +49,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Image Generation Form -->
|
||||
<div class="bg-[#1E293B] border border-[#1E293B] rounded-xl p-6">
|
||||
<h2 class="text-2xl font-bold text-[#E5E7EB] mb-6">Generate an Image</h2>
|
||||
<div class="card p-6">
|
||||
<h2 class="h3 mb-6">Generate an Image</h2>
|
||||
|
||||
<div class="relative">
|
||||
<input id="image-model" type="hidden" value="{{.Model}}">
|
||||
<form id="genimage" action="text2image/{{.Model}}" method="get" class="mb-8">
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 flex items-center pl-4">
|
||||
<i class="fas fa-magic text-[#38BDF8]"></i>
|
||||
<i class="fas fa-magic text-[var(--color-primary)]"></i>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
@@ -79,11 +65,11 @@
|
||||
name="input"
|
||||
placeholder="Describe the image you want to generate..."
|
||||
autocomplete="off"
|
||||
class="form-control block w-full pl-12 pr-12 py-4 text-lg font-normal text-[#E5E7EB] bg-[#101827] bg-clip-padding border border-[#1E293B] rounded-lg transition ease-in-out focus:text-[#E5E7EB] focus:bg-[#101827] focus:border-[#38BDF8] focus:ring-2 focus:ring-[#38BDF8]/50 focus:outline-none"
|
||||
class="input w-full pl-12 pr-12 py-4 text-lg"
|
||||
required
|
||||
/>
|
||||
<span id="loader" class="my-2 loader absolute right-4 top-4 hidden">
|
||||
<svg class="animate-spin h-6 w-6 text-[#38BDF8]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<svg class="animate-spin h-6 w-6 text-[var(--color-primary)]" 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>
|
||||
@@ -92,15 +78,15 @@
|
||||
|
||||
<!-- Size Selection -->
|
||||
<div class="mt-4">
|
||||
<label for="image-size" class="block text-sm font-medium text-[#94A3B8] mb-2">
|
||||
<i class="fas fa-expand-arrows-alt mr-2 text-[#38BDF8]"></i>Image Size:
|
||||
<label for="image-size" class="block text-sm font-medium text-[var(--color-text-secondary)] mb-2">
|
||||
<i class="fas fa-expand-arrows-alt mr-2 text-[var(--color-primary)]"></i>Image Size:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="image-size"
|
||||
value="256x256"
|
||||
placeholder="e.g., 256x256, 512x512, 1024x1024"
|
||||
class="bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#38BDF8] focus:ring-2 focus:ring-[#38BDF8]/50 rounded-lg shadow-sm p-2.5 w-full max-w-xs transition-colors duration-200"
|
||||
class="input p-2.5 w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -108,7 +94,7 @@
|
||||
<div class="mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full bg-[#38BDF8] hover:bg-[#38BDF8]/90 text-[#101827] font-semibold py-3 px-6 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-[#38BDF8] focus:ring-opacity-50"
|
||||
class="btn-primary w-full"
|
||||
>
|
||||
<i class="fas fa-magic mr-2"></i>Generate Image
|
||||
</button>
|
||||
@@ -117,10 +103,10 @@
|
||||
|
||||
<!-- Image Results Container -->
|
||||
<div class="mt-6 border-t border-[#1E293B] pt-6">
|
||||
<h3 class="text-xl font-semibold text-[#E5E7EB] mb-4">Generated Image</h3>
|
||||
<h3 class="text-xl font-semibold text-[var(--color-text-primary)] mb-4">Generated Image</h3>
|
||||
<div class="container mx-auto flex justify-center">
|
||||
<div id="result" class="mx-auto bg-[#101827]/50 border border-[#1E293B] rounded-xl p-4 min-h-[300px] w-full flex items-center justify-center">
|
||||
<p class="text-[#94A3B8] italic">Your generated image will appear here</p>
|
||||
<div id="result" class="mx-auto bg-[var(--color-bg-primary)]/50 border border-[#1E293B] rounded-xl p-4 min-h-[300px] w-full flex items-center justify-center">
|
||||
<p class="text-[var(--color-text-secondary)] italic">Your generated image will appear here</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,27 +9,18 @@
|
||||
{{template "views/partials/navbar" .}}
|
||||
<div class="container mx-auto px-4 py-8 flex-grow">
|
||||
<!-- Hero Section -->
|
||||
<div class="bg-[#1E293B] border border-[#8B5CF6]/20 rounded-xl p-8 mb-10">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-[#E5E7EB] mb-4">
|
||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-[#8B5CF6] to-[#38BDF8]">
|
||||
<i class="fas fa-volume-high mr-2"></i>Text to Speech {{ if .Model }} with {{.Model}} {{ end }}
|
||||
</span>
|
||||
<div class="hero-section">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">
|
||||
<i class="fas fa-volume-high mr-2"></i>Text to Speech {{ if .Model }} with {{.Model}} {{ end }}
|
||||
</h1>
|
||||
<p class="text-xl text-[#94A3B8] mb-6">Convert your text into natural-sounding speech</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="https://localai.io/features/text-to-audio/" target="_blank"
|
||||
class="inline-flex items-center bg-[#8B5CF6] hover:bg-[#8B5CF6]/90 text-white font-semibold py-2 px-6 rounded-lg transition-colors">
|
||||
<i class="fas fa-book-reader mr-2"></i>
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="hero-subtitle">Convert your text into natural-sounding speech</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TTS Interface -->
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="bg-[#1E293B] border border-[#1E293B] rounded-xl overflow-hidden">
|
||||
<div class="card overflow-hidden">
|
||||
<!-- Header with Model Selection -->
|
||||
<div class="border-b border-[#1E293B] p-5">
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||
@@ -42,7 +33,7 @@
|
||||
id="model-select"
|
||||
x-model="link"
|
||||
@change="window.location = link"
|
||||
class="bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#8B5CF6] focus:ring-2 focus:ring-[#8B5CF6]/50 rounded-lg shadow-sm p-2.5 appearance-none"
|
||||
class="input p-2.5"
|
||||
>
|
||||
<option value="" disabled class="text-[#94A3B8]">Select a model</option>
|
||||
{{ $model:=.Model}}
|
||||
@@ -83,10 +74,10 @@
|
||||
name="input"
|
||||
placeholder="Enter text to convert to speech..."
|
||||
autocomplete="off"
|
||||
class="w-full bg-[#101827] text-[#E5E7EB] border border-[#1E293B] focus:border-[#8B5CF6] focus:ring-2 focus:ring-[#8B5CF6]/50 rounded-lg shadow-sm p-4 pl-4 pr-12"
|
||||
class="input w-full p-4 pl-4 pr-12"
|
||||
required
|
||||
/>
|
||||
<button type="submit" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-[#8B5CF6] hover:text-[#38BDF8] transition">
|
||||
<button type="submit" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-[#8B5CF6] hover:text-[#38BDF8] transition icon-hover">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -76,4 +76,34 @@
|
||||
sha: "7f87153bbeb4a7be02520f08d734c004bd09961e2e04cf5ed627173b3ba5f66c"
|
||||
- filename: "autorefresh.min.js"
|
||||
url: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/display/autorefresh.min.js"
|
||||
sha: "bdcc82d01c1cb574d7fb8bbf4938213a81131163375d5c869272de3859245216"
|
||||
sha: "bdcc82d01c1cb574d7fb8bbf4938213a81131163375d5c869272de3859245216"
|
||||
- filename: "playfair-display-regular.ttf"
|
||||
url: "https://fonts.gstatic.com/s/playfairdisplay/v40/nuFvD-vYSZviVYUb_rj3ij__anPXJzDwcbmjWBN2PKdFvUDQ.ttf"
|
||||
sha: "1609a54fa3ad1abc8d0037132f73700333241ea0b65672079998e352f151dea7"
|
||||
- filename: "playfair-display-semibold.ttf"
|
||||
url: "https://fonts.gstatic.com/s/playfairdisplay/v40/nuFvD-vYSZviVYUb_rj3ij__anPXJzDwcbmjWBN2PKebukDQ.ttf"
|
||||
sha: "8ab6a1db2d7caeb46c742371da500d0f3de1dc6ec6bea2aef0106f678d7a1f8d"
|
||||
- filename: "playfair-display-bold.ttf"
|
||||
url: "https://fonts.gstatic.com/s/playfairdisplay/v40/nuFvD-vYSZviVYUb_rj3ij__anPXJzDwcbmjWBN2PKeiukDQ.ttf"
|
||||
sha: "adefc53e7b3d483f1fa5e85edd82b7689ca79db25a1f6786bd7949cdcfeec601"
|
||||
- filename: "space-grotesk-regular.ttf"
|
||||
url: "https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7oUUsj.ttf"
|
||||
sha: "ec926d5065eaca49a48f96e312bbae0bbc5733c24215cf5dfabbdccee926fef7"
|
||||
- filename: "space-grotesk-medium.ttf"
|
||||
url: "https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7aUUsj.ttf"
|
||||
sha: "3e699ead1876244fa392243054ddefe7cf631b488438828a8a100731a22ab995"
|
||||
- filename: "space-grotesk-semibold.ttf"
|
||||
url: "https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj42Vksj.ttf"
|
||||
sha: "6c0346b8d297ebdc225832833e03e884a26ad99d265ecd3924d46e1ba285ea87"
|
||||
- filename: "space-grotesk-bold.ttf"
|
||||
url: "https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj4PVksj.ttf"
|
||||
sha: "3e756954468ff1cb302dae0414262e72f76a67d87bef3fa1f3226cd0fb9b2d85"
|
||||
- filename: "jetbrains-mono-regular.ttf"
|
||||
url: "https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxjPQ.ttf"
|
||||
sha: "44ce4a84f20d60f24539bd0cef11f79c29e38609e0f8adf18551c9794a5d9dc3"
|
||||
- filename: "jetbrains-mono-medium.ttf"
|
||||
url: "https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8-qxjPQ.ttf"
|
||||
sha: "3386a05f6ece969e4537de6be894170d20558e82f7d56c8c5d332972ef172160"
|
||||
- filename: "jetbrains-mono-semibold.ttf"
|
||||
url: "https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8FqtjPQ.ttf"
|
||||
sha: "df54dbfafba61d4911eb3dab9bba2d20531fb009f01d64dd42fa96ab862584d8"
|
||||
Reference in New Issue
Block a user