|
@@ -5,7 +5,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
time: null,
|
|
|
messages: [],
|
|
|
selectedModel: 'llama-3.2-1b',
|
|
|
- },
|
|
|
+ },
|
|
|
|
|
|
// historical state
|
|
|
histories: JSON.parse(localStorage.getItem("histories")) || [],
|
|
@@ -13,7 +13,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
home: 0,
|
|
|
generating: false,
|
|
|
endpoint: `${window.location.origin}/v1`,
|
|
|
-
|
|
|
+
|
|
|
// Initialize error message structure
|
|
|
errorMessage: null,
|
|
|
errorExpanded: false,
|
|
@@ -51,7 +51,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
|
|
|
// Start polling for download progress
|
|
|
this.startDownloadProgressPolling();
|
|
|
-
|
|
|
+
|
|
|
// Start model polling with the new pattern
|
|
|
this.startModelPolling();
|
|
|
},
|
|
@@ -85,14 +85,14 @@ document.addEventListener("alpine:init", () => {
|
|
|
async populateSelector() {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const evtSource = new EventSource(`${window.location.origin}/modelpool`);
|
|
|
-
|
|
|
+
|
|
|
evtSource.onmessage = (event) => {
|
|
|
if (event.data === "[DONE]") {
|
|
|
evtSource.close();
|
|
|
resolve();
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const modelData = JSON.parse(event.data);
|
|
|
// Update existing model data while preserving other properties
|
|
|
Object.entries(modelData).forEach(([modelName, data]) => {
|
|
@@ -105,7 +105,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
evtSource.onerror = (error) => {
|
|
|
console.error('EventSource failed:', error);
|
|
|
evtSource.close();
|
|
@@ -455,7 +455,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
stack: error.stack || ""
|
|
|
};
|
|
|
this.errorExpanded = false;
|
|
|
-
|
|
|
+
|
|
|
if (this.errorTimeout) {
|
|
|
clearTimeout(this.errorTimeout);
|
|
|
}
|
|
@@ -470,10 +470,10 @@ document.addEventListener("alpine:init", () => {
|
|
|
|
|
|
async deleteModel(modelName, model) {
|
|
|
const downloadedSize = model.total_downloaded || 0;
|
|
|
- const sizeMessage = downloadedSize > 0 ?
|
|
|
+ const sizeMessage = downloadedSize > 0 ?
|
|
|
`This will free up ${this.formatBytes(downloadedSize)} of space.` :
|
|
|
'This will remove any partially downloaded files.';
|
|
|
-
|
|
|
+
|
|
|
if (!confirm(`Are you sure you want to delete ${model.name}? ${sizeMessage}`)) {
|
|
|
return;
|
|
|
}
|
|
@@ -487,7 +487,7 @@ document.addEventListener("alpine:init", () => {
|
|
|
});
|
|
|
|
|
|
const data = await response.json();
|
|
|
-
|
|
|
+
|
|
|
if (!response.ok) {
|
|
|
throw new Error(data.detail || 'Failed to delete model');
|
|
|
}
|
|
@@ -562,10 +562,10 @@ document.addEventListener("alpine:init", () => {
|
|
|
initTopology() {
|
|
|
// Initial fetch
|
|
|
this.updateTopology();
|
|
|
-
|
|
|
+
|
|
|
// Set up periodic updates
|
|
|
this.topologyInterval = setInterval(() => this.updateTopology(), 5000);
|
|
|
-
|
|
|
+
|
|
|
// Cleanup on page unload
|
|
|
window.addEventListener('beforeunload', () => {
|
|
|
if (this.topologyInterval) {
|
|
@@ -577,14 +577,24 @@ document.addEventListener("alpine:init", () => {
|
|
|
async updateTopology() {
|
|
|
const topologyData = await this.fetchTopology();
|
|
|
if (!topologyData) return;
|
|
|
-
|
|
|
+
|
|
|
const vizElement = this.$refs.topologyViz;
|
|
|
vizElement.innerHTML = ''; // Clear existing visualization
|
|
|
-
|
|
|
+
|
|
|
// Create nodes from object
|
|
|
Object.entries(topologyData.nodes).forEach(([nodeId, node]) => {
|
|
|
const nodeElement = document.createElement('div');
|
|
|
nodeElement.className = 'topology-node';
|
|
|
+
|
|
|
+ // Get peer connections for this node
|
|
|
+ const peerConnections = topologyData.peer_graph[nodeId] || [];
|
|
|
+ const peerConnectionsHtml = peerConnections.map(peer => `
|
|
|
+ <div class="peer-connection">
|
|
|
+ <i class="fas fa-arrow-right"></i>
|
|
|
+ <span>To ${peer.to_id}: ${peer.description}</span>
|
|
|
+ </div>
|
|
|
+ `).join('');
|
|
|
+
|
|
|
nodeElement.innerHTML = `
|
|
|
<div class="node-info">
|
|
|
<span class="status ${nodeId === topologyData.active_node_id ? 'active' : 'inactive'}"></span>
|
|
@@ -595,6 +605,9 @@ document.addEventListener("alpine:init", () => {
|
|
|
<span>${(node.memory / 1024).toFixed(1)}GB RAM</span>
|
|
|
<span>${node.flops.fp32.toFixed(1)} TF</span>
|
|
|
</div>
|
|
|
+ <div class="peer-connections">
|
|
|
+ ${peerConnectionsHtml}
|
|
|
+ </div>
|
|
|
`;
|
|
|
vizElement.appendChild(nodeElement);
|
|
|
});
|