Avatar Fix , control pannel UI fix

This commit is contained in:
Stijnus
2025-02-03 01:04:23 +01:00
parent f3468d495d
commit f091409f7e
7 changed files with 392 additions and 164 deletions

View File

@@ -9,6 +9,7 @@ import { ScrollArea } from '~/components/ui/ScrollArea';
import { Badge } from '~/components/ui/Badge';
import { Dialog, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
import { jsPDF } from 'jspdf';
import { useSettings } from '~/lib/hooks/useSettings';
interface SystemInfo {
os: string;
@@ -138,6 +139,11 @@ interface OllamaServiceStatus {
isRunning: boolean;
lastChecked: Date;
error?: string;
models?: Array<{
name: string;
size: string;
quantization: string;
}>;
}
interface ExportFormat {
@@ -232,6 +238,8 @@ export default function DebugTab() {
performance: false,
});
const { isLocalModel, providers } = useSettings();
// Subscribe to logStore updates
const logs = useStore(logStore.logs);
const errorLogs = useMemo(() => {
@@ -1093,41 +1101,48 @@ export default function DebugTab() {
];
// Add Ollama health check function
const checkOllamaHealth = async () => {
const checkOllamaStatus = useCallback(async () => {
try {
const response = await fetch('http://127.0.0.1:11434/api/version');
const isHealthy = response.ok;
// First check if service is running
const versionResponse = await fetch('http://127.0.0.1:11434/api/version');
if (!versionResponse.ok) {
throw new Error('Service not running');
}
// Then fetch installed models
const modelsResponse = await fetch('http://127.0.0.1:11434/api/tags');
const modelsData = (await modelsResponse.json()) as {
models: Array<{ name: string; size: string; quantization: string }>;
};
setOllamaStatus({
isRunning: isHealthy,
isRunning: true,
lastChecked: new Date(),
error: isHealthy ? undefined : 'Ollama service is not responding',
models: modelsData.models,
});
return isHealthy;
} catch {
setOllamaStatus({
isRunning: false,
error: 'Connection failed',
lastChecked: new Date(),
error: 'Failed to connect to Ollama service',
models: undefined,
});
return false;
}
};
// Add Ollama health check effect
useEffect(() => {
const checkHealth = async () => {
await checkOllamaHealth();
};
checkHealth();
const interval = setInterval(checkHealth, 30000); // Check every 30 seconds
return () => clearInterval(interval);
}, []);
// Monitor isLocalModel changes and check status periodically
useEffect(() => {
// Check immediately when isLocalModel changes
checkOllamaStatus();
// Set up periodic checks every 10 seconds
const intervalId = setInterval(checkOllamaStatus, 10000);
return () => clearInterval(intervalId);
}, [isLocalModel, checkOllamaStatus]);
// Replace the existing export button with this new component
const ExportButton = () => {
const [isOpen, setIsOpen] = useState(false);
@@ -1199,60 +1214,225 @@ export default function DebugTab() {
);
};
// Add helper function to get Ollama status text and color
const getOllamaStatus = () => {
const ollamaProvider = providers?.Ollama;
const isOllamaEnabled = ollamaProvider?.settings?.enabled;
if (!isLocalModel) {
return {
status: 'Disabled',
color: 'text-red-500',
bgColor: 'bg-red-500',
message: 'Local models are disabled in settings',
};
}
if (!isOllamaEnabled) {
return {
status: 'Disabled',
color: 'text-red-500',
bgColor: 'bg-red-500',
message: 'Ollama provider is disabled in settings',
};
}
if (!ollamaStatus.isRunning) {
return {
status: 'Not Running',
color: 'text-red-500',
bgColor: 'bg-red-500',
message: ollamaStatus.error || 'Ollama service is not running',
};
}
const modelCount = ollamaStatus.models?.length ?? 0;
return {
status: 'Running',
color: 'text-green-500',
bgColor: 'bg-green-500',
message: `Ollama service is running with ${modelCount} installed models (Provider: Enabled)`,
};
};
// Add type for status result
type StatusResult = {
status: string;
color: string;
bgColor: string;
message: string;
};
const status = getOllamaStatus() as StatusResult;
return (
<div className="flex flex-col gap-6 max-w-7xl mx-auto p-4">
{/* Quick Stats Banner */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
{/* Add Ollama Service Status Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="text-sm text-bolt-elements-textSecondary">Ollama Service</div>
{/* Ollama Service Status Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] hover:border-purple-500/30 transition-all duration-200">
<div className="flex items-center gap-2">
<div className="i-ph:robot text-purple-500 w-4 h-4" />
<div className="text-sm text-bolt-elements-textSecondary">Ollama Service</div>
</div>
<div className="flex items-center gap-2 mt-2">
<div
className={classNames(
'w-2 h-2 rounded-full animate-pulse',
ollamaStatus.isRunning ? 'bg-green-500' : 'bg-red-500',
)}
className={classNames('w-2 h-2 rounded-full animate-pulse', status.bgColor, {
'shadow-lg shadow-green-500/20': status.status === 'Running',
'shadow-lg shadow-red-500/20': status.status === 'Not Running',
})}
/>
<span
className={classNames('text-sm font-medium', ollamaStatus.isRunning ? 'text-green-500' : 'text-red-500')}
>
{ollamaStatus.isRunning ? 'Running' : 'Not Running'}
<span className={classNames('text-sm font-medium flex items-center gap-1.5', status.color)}>
{status.status === 'Running' && <div className="i-ph:check-circle-fill w-3.5 h-3.5" />}
{status.status === 'Not Running' && <div className="i-ph:x-circle-fill w-3.5 h-3.5" />}
{status.status === 'Disabled' && <div className="i-ph:prohibit-fill w-3.5 h-3.5" />}
{status.status}
</span>
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2">
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div
className={classNames('w-3.5 h-3.5', {
'i-ph:info text-green-500': status.status === 'Running',
'i-ph:warning text-red-500': status.status === 'Not Running' || status.status === 'Disabled',
})}
/>
{status.message}
</div>
{ollamaStatus.models && ollamaStatus.models.length > 0 && (
<div className="mt-3 space-y-1 border-t border-[#E5E5E5] dark:border-[#1A1A1A] pt-2">
<div className="text-xs font-medium text-bolt-elements-textSecondary flex items-center gap-1.5">
<div className="i-ph:cube-duotone w-3.5 h-3.5 text-purple-500" />
Installed Models
</div>
{ollamaStatus.models.map((model) => (
<div key={model.name} className="text-xs text-bolt-elements-textSecondary flex items-center gap-2 pl-5">
<div className="i-ph:cube w-3 h-3 text-purple-500/70" />
<span className="font-mono">{model.name}</span>
<span className="text-bolt-elements-textTertiary">
({Math.round(parseInt(model.size) / 1024 / 1024)}MB, {model.quantization})
</span>
</div>
))}
</div>
)}
<div className="text-xs text-bolt-elements-textTertiary mt-3 flex items-center gap-1.5">
<div className="i-ph:clock w-3 h-3" />
Last checked: {ollamaStatus.lastChecked.toLocaleTimeString()}
</div>
</div>
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="text-sm text-bolt-elements-textSecondary">Memory Usage</div>
<div className="text-2xl font-semibold text-bolt-elements-textPrimary mt-1">
{systemInfo?.memory.percentage}%
{/* Memory Usage Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] hover:border-purple-500/30 transition-all duration-200">
<div className="flex items-center gap-2">
<div className="i-ph:cpu text-purple-500 w-4 h-4" />
<div className="text-sm text-bolt-elements-textSecondary">Memory Usage</div>
</div>
<Progress value={systemInfo?.memory.percentage || 0} className="mt-2" />
</div>
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="text-sm text-bolt-elements-textSecondary">Page Load Time</div>
<div className="text-2xl font-semibold text-bolt-elements-textPrimary mt-1">
{systemInfo ? (systemInfo.performance.timing.loadTime / 1000).toFixed(2) + 's' : '-'}
<div className="flex items-center gap-2 mt-2">
<span
className={classNames(
'text-2xl font-semibold',
(systemInfo?.memory?.percentage ?? 0) > 80
? 'text-red-500'
: (systemInfo?.memory?.percentage ?? 0) > 60
? 'text-yellow-500'
: 'text-green-500',
)}
>
{systemInfo?.memory?.percentage ?? 0}%
</span>
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2">
DOM Ready: {systemInfo ? (systemInfo.performance.timing.domReadyTime / 1000).toFixed(2) + 's' : '-'}
<Progress
value={systemInfo?.memory?.percentage ?? 0}
className={classNames(
'mt-2',
(systemInfo?.memory?.percentage ?? 0) > 80
? '[&>div]:bg-red-500'
: (systemInfo?.memory?.percentage ?? 0) > 60
? '[&>div]:bg-yellow-500'
: '[&>div]:bg-green-500',
)}
/>
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div className="i-ph:info w-3.5 h-3.5 text-purple-500" />
Used: {systemInfo?.memory.used ?? '0 GB'} / {systemInfo?.memory.total ?? '0 GB'}
</div>
</div>
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="text-sm text-bolt-elements-textSecondary">Network Speed</div>
<div className="text-2xl font-semibold text-bolt-elements-textPrimary mt-1">
{systemInfo?.network.downlink || '-'} Mbps
{/* Page Load Time Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] hover:border-purple-500/30 transition-all duration-200">
<div className="flex items-center gap-2">
<div className="i-ph:timer text-purple-500 w-4 h-4" />
<div className="text-sm text-bolt-elements-textSecondary">Page Load Time</div>
</div>
<div className="flex items-center gap-2 mt-2">
<span
className={classNames(
'text-2xl font-semibold',
(systemInfo?.performance.timing.loadTime ?? 0) > 2000
? 'text-red-500'
: (systemInfo?.performance.timing.loadTime ?? 0) > 1000
? 'text-yellow-500'
: 'text-green-500',
)}
>
{systemInfo ? (systemInfo.performance.timing.loadTime / 1000).toFixed(2) : '-'}s
</span>
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div className="i-ph:code w-3.5 h-3.5 text-purple-500" />
DOM Ready: {systemInfo ? (systemInfo.performance.timing.domReadyTime / 1000).toFixed(2) : '-'}s
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2">RTT: {systemInfo?.network.rtt || '-'} ms</div>
</div>
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="text-sm text-bolt-elements-textSecondary">Errors</div>
<div className="text-2xl font-semibold text-bolt-elements-textPrimary mt-1">{errorLogs.length}</div>
{/* Network Speed Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] hover:border-purple-500/30 transition-all duration-200">
<div className="flex items-center gap-2">
<div className="i-ph:wifi-high text-purple-500 w-4 h-4" />
<div className="text-sm text-bolt-elements-textSecondary">Network Speed</div>
</div>
<div className="flex items-center gap-2 mt-2">
<span
className={classNames(
'text-2xl font-semibold',
(systemInfo?.network.downlink ?? 0) < 5
? 'text-red-500'
: (systemInfo?.network.downlink ?? 0) < 10
? 'text-yellow-500'
: 'text-green-500',
)}
>
{systemInfo?.network.downlink ?? '-'} Mbps
</span>
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div className="i-ph:activity w-3.5 h-3.5 text-purple-500" />
RTT: {systemInfo?.network.rtt ?? '-'} ms
</div>
</div>
{/* Errors Card */}
<div className="p-4 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] hover:border-purple-500/30 transition-all duration-200">
<div className="flex items-center gap-2">
<div className="i-ph:warning-octagon text-purple-500 w-4 h-4" />
<div className="text-sm text-bolt-elements-textSecondary">Errors</div>
</div>
<div className="flex items-center gap-2 mt-2">
<span
className={classNames('text-2xl font-semibold', errorLogs.length > 0 ? 'text-red-500' : 'text-green-500')}
>
{errorLogs.length}
</span>
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div
className={classNames(
'w-3.5 h-3.5',
errorLogs.length > 0 ? 'i-ph:warning text-red-500' : 'i-ph:check-circle text-green-500',
)}
/>
{errorLogs.length > 0 ? 'Errors detected' : 'No errors detected'}
</div>
</div>
</div>

View File

@@ -87,19 +87,10 @@ export default function LocalProvidersTab() {
.map(([key, value]) => {
const provider = value as IProviderConfig;
const envKey = providerBaseUrlEnvKeys[key]?.baseUrlKey;
// Get environment URL safely
const envUrl = envKey ? (import.meta.env[envKey] as string | undefined) : undefined;
console.log(`Checking env URL for ${key}:`, {
envKey,
envUrl,
currentBaseUrl: provider.settings.baseUrl,
});
// If there's an environment URL and no base URL set, update it
// Set base URL if provided by environment
if (envUrl && !provider.settings.baseUrl) {
console.log(`Setting base URL for ${key} from env:`, envUrl);
updateProviderSettings(key, {
...provider.settings,
baseUrl: envUrl,
@@ -414,7 +405,9 @@ export default function LocalProvidersTab() {
<BiChip className="w-6 h-6" />
</motion.div>
<div>
<h2 className="text-lg font-semibold text-bolt-elements-textPrimary">Local AI Models</h2>
<div className="flex items-center gap-2">
<h2 className="text-lg font-semibold text-bolt-elements-textPrimary">Local AI Models</h2>
</div>
<p className="text-sm text-bolt-elements-textSecondary">Configure and manage your local AI providers</p>
</div>
</div>