← back to Exo
add topology to tinychat ui
036224f877a1c516f14d4e15b701494af3814583 · 2024-12-16 21:17:12 +0000 · Alex Cheema
Files touched
M exo/api/chatgpt_api.pyM exo/tinychat/index.cssM exo/tinychat/index.htmlM exo/tinychat/index.js
Diff
commit 036224f877a1c516f14d4e15b701494af3814583
Author: Alex Cheema <alexcheema123@gmail.com>
Date: Mon Dec 16 21:17:12 2024 +0000
add topology to tinychat ui
---
exo/api/chatgpt_api.py | 1 +
exo/tinychat/index.css | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
exo/tinychat/index.html | 15 +++++++++++
exo/tinychat/index.js | 55 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 138 insertions(+)
diff --git a/exo/api/chatgpt_api.py b/exo/api/chatgpt_api.py
index 68274696..5bc9fb96 100644
--- a/exo/api/chatgpt_api.py
+++ b/exo/api/chatgpt_api.py
@@ -188,6 +188,7 @@ class ChatGPTAPI:
cors.add(self.app.router.add_get("/initial_models", self.handle_get_initial_models), {"*": cors_options})
cors.add(self.app.router.add_post("/create_animation", self.handle_create_animation), {"*": cors_options})
cors.add(self.app.router.add_post("/download", self.handle_post_download), {"*": cors_options})
+ cors.add(self.app.router.add_get("/v1/topology", self.handle_get_topology), {"*": cors_options})
cors.add(self.app.router.add_get("/topology", self.handle_get_topology), {"*": cors_options})
if "__compiled__" not in globals():
diff --git a/exo/tinychat/index.css b/exo/tinychat/index.css
index b8a6751c..95c1a905 100644
--- a/exo/tinychat/index.css
+++ b/exo/tinychat/index.css
@@ -654,4 +654,71 @@ main {
.model-download-button i {
font-size: 0.9em;
+}
+
+.topology-section {
+ margin-bottom: 30px;
+ padding: 15px;
+ background: rgba(255, 255, 255, 0.05);
+ border-radius: 8px;
+}
+
+.topology-visualization {
+ min-height: 150px;
+ position: relative;
+ margin-top: 10px;
+}
+
+.topology-loading {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: #666;
+ font-size: 0.9em;
+}
+
+.topology-node {
+ padding: 8px;
+ background: rgba(255, 255, 255, 0.05);
+ border-radius: 4px;
+ margin: 4px 0;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.node-info {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.9em;
+}
+
+.topology-node .status {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.topology-node .status.active {
+ background: #4CAF50;
+}
+
+.topology-node .status.inactive {
+ background: #666;
+}
+
+.node-details {
+ padding-left: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ font-size: 0.8em;
+ opacity: 0.6;
+}
+
+.node-details span {
+ display: flex;
+ align-items: center;
}
\ No newline at end of file
diff --git a/exo/tinychat/index.html b/exo/tinychat/index.html
index e738b597..879b1fa7 100644
--- a/exo/tinychat/index.html
+++ b/exo/tinychat/index.html
@@ -26,6 +26,21 @@
<body>
<main x-data="state" x-init="console.log(endpoint)">
<div class="sidebar">
+ <!-- Add topology section -->
+ <div class="topology-section">
+ <h2 class="megrim-regular">Network Topology</h2>
+ <div class="topology-visualization"
+ x-init="initTopology()"
+ x-ref="topologyViz">
+ <!-- Loading indicator for topology -->
+ <div class="topology-loading" x-show="!topology">
+ <i class="fas fa-spinner fa-spin"></i>
+ <span>Loading topology...</span>
+ </div>
+ <!-- Topology visualization will be rendered here -->
+ </div>
+ </div>
+
<h2 class="megrim-regular" style="margin-bottom: 20px;">Models</h2>
<!-- Loading indicator -->
diff --git a/exo/tinychat/index.js b/exo/tinychat/index.js
index b559f173..e909a57f 100644
--- a/exo/tinychat/index.js
+++ b/exo/tinychat/index.js
@@ -39,6 +39,9 @@ document.addEventListener("alpine:init", () => {
// Add models state alongside existing state
models: {},
+ topology: null,
+ topologyInterval: null,
+
init() {
// Clean up any pending messages
localStorage.removeItem("pendingMessage");
@@ -543,6 +546,58 @@ document.addEventListener("alpine:init", () => {
console.error('Error starting download:', error);
this.setError(error);
}
+ },
+
+ async fetchTopology() {
+ try {
+ const response = await fetch(`${this.endpoint}/topology`);
+ if (!response.ok) throw new Error('Failed to fetch topology');
+ return await response.json();
+ } catch (error) {
+ console.error('Topology fetch error:', error);
+ return null;
+ }
+ },
+
+ 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) {
+ clearInterval(this.topologyInterval);
+ }
+ });
+ },
+
+ 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';
+ nodeElement.innerHTML = `
+ <div class="node-info">
+ <span class="status ${nodeId === topologyData.active_node_id ? 'active' : 'inactive'}"></span>
+ <span>${node.model}</span>
+ </div>
+ <div class="node-details">
+ <span>${node.chip}</span>
+ <span>${(node.memory / 1024).toFixed(1)}GB RAM</span>
+ <span>${node.flops.fp32.toFixed(1)} TF</span>
+ </div>
+ `;
+ vizElement.appendChild(nodeElement);
+ });
}
}));
});
← b17faa81 dont broadcast every single process_tensor
·
back to Exo
·
make device_capabilities async running on a thread pool 1b14be60 →