fix: model repo subdir layout, no-window engine launch, deploy progress, engine path auto-repair
This commit is contained in:
+7
-1
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { NavLink, Route, Routes } from "react-router-dom";
|
||||
import { EngineDeployEvent, onEvent } from "./api";
|
||||
import { EngineDeployEvent, EngineDeployProgressEvent, onEvent } from "./api";
|
||||
import { useStore } from "./store";
|
||||
import Icon from "./components/Icon";
|
||||
import ModelsPage from "./pages/ModelsPage";
|
||||
@@ -26,6 +26,7 @@ export default function App() {
|
||||
const refreshServer = useStore((s) => s.refreshServer);
|
||||
const refreshConversations = useStore((s) => s.refreshConversations);
|
||||
const setDeployState = useStore((s) => s.setDeployState);
|
||||
const setDeployProgress = useStore((s) => s.setDeployProgress);
|
||||
|
||||
function toggleCollapsed() {
|
||||
setCollapsed((v) => {
|
||||
@@ -48,12 +49,16 @@ export default function App() {
|
||||
setDeployState(e.model_id, e.state);
|
||||
refreshEngine();
|
||||
});
|
||||
const un6 = onEvent<EngineDeployProgressEvent>("engine://deploy-progress", (e) => {
|
||||
setDeployProgress(e.model_id, { percent: e.percent, stage: e.stage });
|
||||
});
|
||||
return () => {
|
||||
un1.then((f) => f());
|
||||
un2.then((f) => f());
|
||||
un3.then((f) => f());
|
||||
un4.then((f) => f());
|
||||
un5.then((f) => f());
|
||||
un6.then((f) => f());
|
||||
};
|
||||
}, [
|
||||
refreshModels,
|
||||
@@ -61,6 +66,7 @@ export default function App() {
|
||||
refreshServer,
|
||||
refreshConversations,
|
||||
setDeployState,
|
||||
setDeployProgress,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -115,6 +115,13 @@ export interface EngineDeployEvent {
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface EngineDeployProgressEvent {
|
||||
model_id: string;
|
||||
file_name: string;
|
||||
percent: number;
|
||||
stage: string;
|
||||
}
|
||||
|
||||
export interface DownloadProgressEvent {
|
||||
id: string;
|
||||
url: string;
|
||||
|
||||
@@ -181,6 +181,8 @@ export default function ChatPage() {
|
||||
|
||||
const engineRunning = useStore((s) => s.engine?.running ?? false);
|
||||
const engineModel = useStore((s) => s.engine?.model ?? null);
|
||||
const deployStates = useStore((s) => s.deployStates);
|
||||
const deployProgress = useStore((s) => s.deployProgress);
|
||||
const selectedIsRemote = useMemo(
|
||||
() => models.find((m) => m.id === selectedModelId)?.kind === "remote",
|
||||
[models, selectedModelId],
|
||||
@@ -338,6 +340,22 @@ export default function ChatPage() {
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{deployStates[selectedModelId] === "loading" ? (
|
||||
<div className="mt-2">
|
||||
<div className="h-1.5 overflow-hidden rounded-full bg-panel-2">
|
||||
<div
|
||||
className="h-full rounded-full bg-gradient-to-r from-accent to-accent-2 transition-all duration-300"
|
||||
style={{
|
||||
width: `${deployProgress[selectedModelId]?.percent ?? 8}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-1 text-[10px] text-slate-400">
|
||||
{deployProgress[selectedModelId]?.stage ?? "启动引擎进程"}{" "}
|
||||
{deployProgress[selectedModelId]?.percent ?? 8}%
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-1 truncate text-xs text-slate-500">{engineLabel}</div>
|
||||
|
||||
<div className="mt-4 border-t border-border pt-3">
|
||||
|
||||
@@ -13,6 +13,7 @@ export default function ModelsPage() {
|
||||
const refreshModels = useStore((s) => s.refreshModels);
|
||||
const engine = useStore((s) => s.engine);
|
||||
const deployStates = useStore((s) => s.deployStates);
|
||||
const deployProgress = useStore((s) => s.deployProgress);
|
||||
const [showRemoteForm, setShowRemoteForm] = useState(false);
|
||||
const [scanning, setScanning] = useState(false);
|
||||
const [remote, setRemote] = useState({
|
||||
@@ -249,6 +250,7 @@ export default function ModelsPage() {
|
||||
engineRunning={engine?.running ?? false}
|
||||
deployed={engine?.model === m.file_name}
|
||||
deployState={deployStates[m.id]}
|
||||
deployProgress={deployProgress[m.id]}
|
||||
onDeploy={handleDeploy}
|
||||
onStop={handleStopEngine}
|
||||
/>
|
||||
@@ -276,6 +278,7 @@ function DeployButton({
|
||||
engineRunning,
|
||||
deployed,
|
||||
deployState,
|
||||
deployProgress,
|
||||
onDeploy,
|
||||
onStop,
|
||||
}: {
|
||||
@@ -283,6 +286,7 @@ function DeployButton({
|
||||
engineRunning: boolean;
|
||||
deployed: boolean;
|
||||
deployState?: string;
|
||||
deployProgress?: { percent: number; stage: string };
|
||||
onDeploy: (id: string) => void;
|
||||
onStop: () => void;
|
||||
}) {
|
||||
@@ -303,10 +307,19 @@ function DeployButton({
|
||||
);
|
||||
}
|
||||
if (deployState === "loading") {
|
||||
const p = deployProgress ?? { percent: 8, stage: "启动引擎进程" };
|
||||
return (
|
||||
<button className="btn-secondary !px-3 !py-1 text-xs" disabled>
|
||||
部署中…
|
||||
</button>
|
||||
<div className="w-36">
|
||||
<div className="h-1.5 overflow-hidden rounded-full bg-panel-2">
|
||||
<div
|
||||
className="h-full rounded-full bg-gradient-to-r from-accent to-accent-2 transition-all duration-300"
|
||||
style={{ width: `${p.percent}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-1 truncate text-[10px] text-slate-400">
|
||||
{p.stage} {p.percent}%
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,9 @@ interface Store {
|
||||
server: ServerStatus | null;
|
||||
conversations: Conversation[];
|
||||
deployStates: Record<string, string>;
|
||||
deployProgress: Record<string, { percent: number; stage: string }>;
|
||||
setDeployState: (modelId: string, state: string) => void;
|
||||
setDeployProgress: (modelId: string, progress: { percent: number; stage: string }) => void;
|
||||
refreshModels: () => Promise<void>;
|
||||
refreshEngine: () => Promise<void>;
|
||||
refreshServer: () => Promise<void>;
|
||||
@@ -20,8 +22,11 @@ export const useStore = create<Store>((set) => ({
|
||||
server: null,
|
||||
conversations: [],
|
||||
deployStates: {},
|
||||
deployProgress: {},
|
||||
setDeployState: (modelId, state) =>
|
||||
set((s) => ({ deployStates: { ...s.deployStates, [modelId]: state } })),
|
||||
setDeployProgress: (modelId, progress) =>
|
||||
set((s) => ({ deployProgress: { ...s.deployProgress, [modelId]: progress } })),
|
||||
refreshModels: async () => set({ models: await api.listModels() }),
|
||||
refreshEngine: async () => set({ engine: await api.engineStatus() }),
|
||||
refreshServer: async () => set({ server: await api.serverStatus() }),
|
||||
|
||||
Reference in New Issue
Block a user