add toggle to hide/show unlisted models (#187)

This commit is contained in:
Benson Wong
2025-07-02 16:14:20 -07:00
committed by GitHub
parent 6a058e4191
commit 78b2bc3dbc
3 changed files with 24 additions and 12 deletions

View File

@@ -15,6 +15,7 @@ type Model struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
State string `json:"state"` State string `json:"state"`
Unlisted bool `json:"unlisted"`
} }
func addApiHandlers(pm *ProxyManager) { func addApiHandlers(pm *ProxyManager) {
@@ -72,6 +73,7 @@ func (pm *ProxyManager) getModelStatus() []Model {
Name: pm.config.Models[modelID].Name, Name: pm.config.Models[modelID].Name,
Description: pm.config.Models[modelID].Description, Description: pm.config.Models[modelID].Description,
State: state, State: state,
Unlisted: pm.config.Models[modelID].Unlisted,
}) })
} }

View File

@@ -8,6 +8,7 @@ export interface Model {
state: ModelStatus; state: ModelStatus;
name: string; name: string;
description: string; description: string;
unlisted: boolean;
} }
interface APIProviderType { interface APIProviderType {
@@ -58,7 +59,6 @@ export function APIProvider({ children }: APIProviderProps) {
} }
let retryCount = 0; let retryCount = 0;
const maxRetries = 3;
const initialDelay = 1000; // 1 second const initialDelay = 1000; // 1 second
const connect = () => { const connect = () => {
@@ -93,11 +93,9 @@ export function APIProvider({ children }: APIProviderProps) {
}; };
eventSource.onerror = () => { eventSource.onerror = () => {
eventSource.close(); eventSource.close();
if (retryCount < maxRetries) { retryCount++;
retryCount++; const delay = Math.min(initialDelay * Math.pow(2, retryCount - 1), 5000);
const delay = initialDelay * Math.pow(2, retryCount - 1); setTimeout(connect, delay);
setTimeout(connect, delay);
}
}; };
apiEventSource.current = eventSource; apiEventSource.current = eventSource;

View File

@@ -2,10 +2,16 @@ import { useState, useEffect, useCallback, useMemo } from "react";
import { useAPI } from "../contexts/APIProvider"; import { useAPI } from "../contexts/APIProvider";
import { LogPanel } from "./LogViewer"; import { LogPanel } from "./LogViewer";
import { processEvalTimes } from "../lib/Utils"; import { processEvalTimes } from "../lib/Utils";
import { usePersistentState } from "../hooks/usePersistentState";
export default function ModelsPage() { export default function ModelsPage() {
const { models, unloadAllModels, loadModel, upstreamLogs, enableAPIEvents } = useAPI(); const { models, unloadAllModels, loadModel, upstreamLogs, enableAPIEvents } = useAPI();
const [isUnloading, setIsUnloading] = useState(false); const [isUnloading, setIsUnloading] = useState(false);
const [showUnlisted, setShowUnlisted] = usePersistentState("showUnlisted", true);
const filteredModels = useMemo(() => {
return models.filter((model) => showUnlisted || !model.unlisted);
}, [models, showUnlisted]);
useEffect(() => { useEffect(() => {
enableAPIEvents(true); enableAPIEvents(true);
@@ -39,9 +45,15 @@ export default function ModelsPage() {
<div className="w-full md:w-1/2 flex items-top"> <div className="w-full md:w-1/2 flex items-top">
<div className="card w-full"> <div className="card w-full">
<h2 className="">Models</h2> <h2 className="">Models</h2>
<button className="btn" onClick={handleUnloadAllModels} disabled={isUnloading}> <div className="flex justify-between">
{isUnloading ? "Unloading..." : "Unload All Models"} <button className="btn" onClick={() => setShowUnlisted(!showUnlisted)} style={{ lineHeight: "1.2" }}>
</button> {showUnlisted ? "🟢 unlisted" : "⚫️ unlisted"}
</button>
<button className="btn" onClick={handleUnloadAllModels} disabled={isUnloading}>
{isUnloading ? "Stopping ..." : "Stop All"}
</button>
</div>
<table className="w-full mt-4"> <table className="w-full mt-4">
<thead> <thead>
<tr className="border-b border-primary"> <tr className="border-b border-primary">
@@ -51,7 +63,7 @@ export default function ModelsPage() {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{models.map((model) => ( {filteredModels.map((model) => (
<tr key={model.id} className="border-b hover:bg-secondary-hover border-border"> <tr key={model.id} className="border-b hover:bg-secondary-hover border-border">
<td className="p-2"> <td className="p-2">
<a href={`/upstream/${model.id}/`} className="underline" target="_blank"> <a href={`/upstream/${model.id}/`} className="underline" target="_blank">
@@ -63,7 +75,7 @@ export default function ModelsPage() {
</p> </p>
)} )}
</td> </td>
<td className="p-2"> <td className="p-2 w-[50px]">
<button <button
className="btn btn--sm" className="btn btn--sm"
disabled={model.state !== "stopped"} disabled={model.state !== "stopped"}
@@ -72,7 +84,7 @@ export default function ModelsPage() {
Load Load
</button> </button>
</td> </td>
<td className="p-2"> <td className="p-2 w-[75px]">
<span className={`status status--${model.state}`}>{model.state}</span> <span className={`status status--${model.state}`}>{model.state}</span>
</td> </td>
</tr> </tr>