Files
embeddingsearch/src/Server/Views/Home/Index.cshtml

306 lines
14 KiB
Plaintext

@using Server.Models
@using System.Web
@using Shared.Models
@using Server.Services
@using Server
@inject LocalizationService T
@model HomeIndexViewModel
@{
ViewData["Title"] = "Home Page";
bool hasName = User.Identity?.Name is not null;
string name = "";
if (hasName && User.Identity is not null && User.Identity.Name is not null)
{
name = User.Identity.Name;
}
}
<div class="container py-4">
<h1 class="visually-hidden">Searchdomains</h1>
<p class="mb-4 fs-3">
@(hasName ? T["Hi, {0}!", name] : T["Hi!"])
</p>
<div class="row g-4">
<!-- Server -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-body">
<h2 class="card-title fs-5">@T["Server"]</h2>
<div class="d-flex justify-content-between mt-2">
<span>@T["Total RAM usage"]</span>
<strong id="serverMemorySize"></strong>
</div>
<div class="d-flex justify-content-between mt-2">
<span>@T["Total Database size"]</span>
<strong id="serverDatabaseSize"></strong>
</div>
</div>
</div>
</div>
<!-- Embedding Cache -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-body">
<h2 class="card-title fs-5">@T["Embedding Cache"]</h2>
<div class="d-flex justify-content-between">
<span>@T["Size"]</span>
<strong id="embeddingcacheSize"></strong>
</div>
<div class="d-flex justify-content-between mt-2">
<span>
@T["Strings"]
<i class="bi bi-info-circle-fill text-info"
data-bs-toggle="tooltip"
title="@T["stringsCountInfo"]"></i>
</span>
<strong id="embeddingcacheElementCount"></strong>
</div>
<div class="progress mt-3" style="height: 8px;">
<div id="embeddingcacheElementCountProgressBar" class="progress-bar"
style="width: 0.00%"></div>
</div>
<div class="d-flex justify-content-between mt-2">
<span>@T["Embeddings"]</span>
<strong id="embeddingcacheEmbeddingCount"></strong>
</div>
</div>
</div>
</div>
<!-- Health Checks -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-body">
<h2 class="card-title fs-5">@T["Health Checks"]</h2>
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between">
<span>@T["Server"]</span>
<span id="healthchecksServer"
class="badge bg-warning">
???????
</span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span>@T["AI Providers"]</span>
<span id="healthchecksAiProvider"
class="badge bg-warning">
???????
</span>
</li>
</ul>
</div>
</div>
</div>
<!-- Searchdomains -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-body">
<h2 class="card-title fs-5">@T["Searchdomains"]</h2>
<div class="d-flex justify-content-between">
<span>@T["Count"]</span>
<strong id="searchdomainCount"></strong>
</div>
<div class="d-flex justify-content-between mt-2">
<span>@T["Total Entities"]</span>
<strong id="searchdomainEntityCount"></strong>
</div>
<div class="d-flex justify-content-between mt-2">
<span>@T["Total query cache utilization"]</span>
<strong id="totalQuerycacheUtilization"></strong>
</div>
<!-- Query cache -->
<div class="d-flex justify-content-between mt-2">
<span>@T["Query cache entry count"]</span>
<strong id="querycacheCount"></strong>
</div>
<div class="d-flex justify-content-between mt-2">
<span>
@T["Query cache capacity (loaded)"]
<i class="bi bi-info-circle-fill text-info"
data-bs-toggle="tooltip"
title="@T["queryCacheEntryCountLoadedInfo"]"></i>
</span>
<strong id="querycacheLoadedMaxElementCount"></strong>
</div>
<div class="progress mt-3" style="height: 8px;">
<div id="querycacheLoadedMaxElementCountProgressBar" class="progress-bar"
style="width: 0.00%"></div>
</div>
<div class="d-flex justify-content-between mt-2">
<span>
@T["Query cache capacity (all)"]
<i class="bi bi-info-circle-fill text-info"
data-bs-toggle="tooltip"
title="@T["queryCacheEntryCountAllInfo"]"></i>
</span>
<strong id="querycacheMaxElementCount"></strong>
</div>
<div class="progress mt-3" style="height: 8px;">
<div id="querycacheMaxElementCountProgressBar" class="progress-bar"
style="width: 0.00%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var searchdomains = null;
document.addEventListener('DOMContentLoaded', async () => {
let searchdomainCount = document.getElementById("searchdomainCount");
showThrobber(searchdomainCount);
let searchdomainEntityCount = document.getElementById("searchdomainEntityCount");
showThrobber(searchdomainEntityCount);
let totalQuerycacheUtilization = document.getElementById("totalQuerycacheUtilization");
showThrobber(totalQuerycacheUtilization);
let embeddingcacheSize = document.getElementById("embeddingcacheSize");
showThrobber(embeddingcacheSize);
let embeddingcacheElementCount = document.getElementById("embeddingcacheElementCount");
showThrobber(embeddingcacheElementCount);
let embeddingcacheEmbeddingCount = document.getElementById("embeddingcacheEmbeddingCount");
showThrobber(embeddingcacheEmbeddingCount);
let embeddingcacheElementCountProgressBar = document.getElementById("embeddingcacheElementCountProgressBar");
let querycacheCount = document.getElementById("querycacheCount");
showThrobber(querycacheCount);
let querycacheMaxElementCount = document.getElementById("querycacheMaxElementCount");
showThrobber(querycacheMaxElementCount);
let querycacheMaxElementCountProgressBar = document.getElementById("querycacheMaxElementCountProgressBar");
let querycacheLoadedMaxElementCount = document.getElementById("querycacheLoadedMaxElementCount");
showThrobber(querycacheLoadedMaxElementCount);
let querycacheLoadedElementCountProgressBar = document.getElementById("querycacheLoadedElementCountProgressBar");
let serverMemorySize = document.getElementById("serverMemorySize");
showThrobber(serverMemorySize);
let serverDatabaseSize = document.getElementById("serverDatabaseSize");
showThrobber(serverDatabaseSize);
let healthchecksServer = document.getElementById("healthchecksServer");
let healthchecksAiProvider = document.getElementById("healthchecksAiProvider");
(async() => {
listSearchdomains().then(async result => {
searchdomains = result.Searchdomains;
hideThrobber(searchdomainCount);
searchdomainCount.textContent = searchdomains.length;
});
getServerStats().then(result => {
let utilization = result.EmbeddingCacheUtilization;
let embeddingCacheMaxElementCount = result.EmbeddingCacheMaxElementCount;
let embeddingCacheElementCount = result.ElementCount;
let embeddingCount = result.EmbeddingsCount;
let entityCount = result.EntityCount;
let queryCacheUtilization = result.QueryCacheUtilization;
let queryCacheElementCount = result.QueryCacheElementCount;
let queryCacheMaxElementCountAll = result.QueryCacheMaxElementCountAll;
let queryCacheMaxElementCountLoadedSearchdomainsOnly = result.QueryCacheMaxElementCountLoadedSearchdomainsOnly;
hideThrobber(embeddingcacheSize);
embeddingcacheSize.textContent = NumberOfBytesAsHumanReadable(utilization);
hideThrobber(embeddingcacheElementCount);
embeddingcacheElementCount.textContent = `${embeddingCacheElementCount.toLocaleString()} / ${embeddingCacheMaxElementCount.toLocaleString()}`;
hideThrobber(embeddingcacheEmbeddingCount);
embeddingcacheEmbeddingCount.textContent = embeddingCount;
embeddingcacheElementCountProgressBar.style.width = `${embeddingCacheElementCount / embeddingCacheMaxElementCount * 100}%`;
hideThrobber(searchdomainEntityCount);
searchdomainEntityCount.textContent = entityCount;
hideThrobber(totalQuerycacheUtilization);
totalQuerycacheUtilization.textContent = NumberOfBytesAsHumanReadable(queryCacheUtilization);
hideThrobber(querycacheMaxElementCount);
querycacheCount.textContent = queryCacheElementCount;
hideThrobber(querycacheCount);
querycacheMaxElementCount.textContent = queryCacheMaxElementCountAll.toLocaleString();
querycacheMaxElementCountProgressBar.style.width = `${queryCacheElementCount / queryCacheMaxElementCountAll * 100}%`;
hideThrobber(querycacheLoadedMaxElementCount);
querycacheLoadedMaxElementCount.textContent = queryCacheMaxElementCountLoadedSearchdomainsOnly.toLocaleString();
querycacheLoadedMaxElementCountProgressBar.style.width = `${queryCacheElementCount / queryCacheMaxElementCountLoadedSearchdomainsOnly * 100}%`;
serverMemorySize.textContent = NumberOfBytesAsHumanReadable(result.RamTotalSize);
hideThrobber(serverMemorySize);
serverDatabaseSize.textContent = NumberOfBytesAsHumanReadable(result.DatabaseTotalSize);
hideThrobber(serverDatabaseSize);
});
getHealthCheckStatusAndApply(healthchecksServer, "/healthz/Database");
getHealthCheckStatusAndApply(healthchecksAiProvider, "/healthz/AIProvider");
})();
});
async function listSearchdomains() {
return await fetch(`/Searchdomains`)
.then(r => r.json());
}
async function listEntities(searchdomain) {
return await fetch(`/Entities?searchdomain=${searchdomain}`)
.then(r => r.json());
}
async function getQuerycacheUtilization(searchdomain) {
return await fetch(`/Searchdomain/QueryCache/Size?searchdomain=${searchdomain}`)
.then(r => r.json());
}
async function getServerStats() {
return await fetch(`/Server/Stats`)
.then(r => r.json());
}
async function getHealthCheckStatusAndApply(element, url) {
let text = await fetch(url)
.then(r => r.text());
let states = {"Healthy": "bg-success", "Degraded": "bg-warning", "Unhealthy": "bg-danger"};
for (let state in states) {
element.classList.remove(states[state]);
}
if (states[text]) {
element.classList.add(states[text]);
} else {
element.classList.add("bg-danger");
}
element.textContent = text;
}
function showThrobber(element = null) {
if (element == null) element = document;
element.classList.add('spinner');
}
function hideThrobber(element = null) {
if (element == null) element = document;
element.classList.remove('spinner');
}
function NumberOfBytesAsHumanReadable(bytes, decimals = 2) {
if (bytes === 0) return '0 B';
if (bytes > 1.20892581961*(10**27)) return "∞ B";
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
const unitIndex = Math.floor(Math.log2(bytes) / 10);
const unit = units[Math.min(unitIndex, units.length - 1)];
const value = bytes / Math.pow(1024, unitIndex);
return `${value.toFixed(decimals)} ${unit}`;
}
</script>