diff --git a/aha-ui/src/App.tsx b/aha-ui/src/App.tsx deleted file mode 100644 index e4bb973..0000000 --- a/aha-ui/src/App.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useState } from "react" -import Sidebar, { type PageView } from "./components/Sidebar" -import ModelsPage from "./pages/ModelsPage" -import LaunchPage from "./pages/LaunchPage" -import "./index.css" - -function App() { - const [activePage, setActivePage] = useState("models") - const [address, setAddress] = useState("127.0.0.1") - const [port, setPort] = useState("10100") - - return ( -
- -
- {activePage === "models" ? ( - - ) : ( - - )} -
-
- ) -} - -export default App diff --git a/aha-ui/src/index.css b/aha-ui/src/index.css deleted file mode 100644 index 7cb39ab..0000000 --- a/aha-ui/src/index.css +++ /dev/null @@ -1,152 +0,0 @@ -@import "tailwindcss"; -@import "tw-animate-css"; -@import "shadcn/tailwind.css"; -@import "@fontsource-variable/geist"; - -@custom-variant dark (&:is(.dark *)); -@custom-variant dark (&:is(.dark *)); - - - -* { - border-color: var(--border); -} - -body { - background-color: var(--background); - color: var(--foreground); - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; -} - -/* Log terminal area */ -.log-area { - font-family: "Cascadia Code", "Fira Code", "JetBrains Mono", monospace; - font-size: 13px; - line-height: 1.5; -} - - - - - -@theme inline { - --font-heading: var(--font-sans); - --font-sans: 'Geist Variable', sans-serif; - --color-sidebar-ring: var(--sidebar-ring); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar: var(--sidebar); - --color-chart-5: var(--chart-5); - --color-chart-4: var(--chart-4); - --color-chart-3: var(--chart-3); - --color-chart-2: var(--chart-2); - --color-chart-1: var(--chart-1); - --color-ring: var(--ring); - --color-input: var(--input); - --color-border: var(--border); - --color-destructive: var(--destructive); - --color-accent-foreground: var(--accent-foreground); - --color-accent: var(--accent); - --color-muted-foreground: var(--muted-foreground); - --color-muted: var(--muted); - --color-secondary-foreground: var(--secondary-foreground); - --color-secondary: var(--secondary); - --color-primary-foreground: var(--primary-foreground); - --color-primary: var(--primary); - --color-popover-foreground: var(--popover-foreground); - --color-popover: var(--popover); - --color-card-foreground: var(--card-foreground); - --color-card: var(--card); - --color-foreground: var(--foreground); - --color-background: var(--background); - --radius-sm: calc(var(--radius) * 0.6); - --radius-md: calc(var(--radius) * 0.8); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) * 1.4); - --radius-2xl: calc(var(--radius) * 1.8); - --radius-3xl: calc(var(--radius) * 2.2); - --radius-4xl: calc(var(--radius) * 2.6); -} - -:root { - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0.042 265.755); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.965 0.001 286.375); - --secondary-foreground: oklch(0.205 0.042 265.755); - --muted: oklch(0.965 0.001 286.375); - --muted-foreground: oklch(0.556 0.027 264.364); - --accent: oklch(0.965 0.001 286.375); - --accent-foreground: oklch(0.205 0.042 265.755); - --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0.004 286.375); - --input: oklch(0.922 0.004 286.375); - --ring: oklch(0.708 0.015 286.375); - --radius: 0.625rem; - --sidebar-background: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.556 0.027 264.364); - --sidebar-primary: oklch(0.205 0.042 265.755); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.965 0.001 286.375); - --sidebar-accent-foreground: oklch(0.205 0.042 265.755); - --sidebar-border: oklch(0.922 0.004 286.375); - --sidebar-ring: oklch(0.708 0.015 286.375); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.87 0 0); - --chart-2: oklch(0.556 0 0); - --chart-3: oklch(0.439 0 0); - --chart-4: oklch(0.371 0 0); - --chart-5: oklch(0.269 0 0); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); -} - -@layer base { - * { - @apply border-border outline-ring/50; - } - - body { - @apply bg-background text-foreground; - } - - html { - @apply font-sans; - } -} \ No newline at end of file diff --git a/aha-ui/src/pages/LaunchPage.tsx b/aha-ui/src/pages/LaunchPage.tsx deleted file mode 100644 index adb20de..0000000 --- a/aha-ui/src/pages/LaunchPage.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { useState, useEffect, useRef, useCallback } from "react" -import { invoke } from "@tauri-apps/api/core" -import { listen } from "@tauri-apps/api/event" -import { Play, Square, Terminal, RotateCw, Server } from "lucide-react" -import { cn } from "../lib/utils" - -interface ModelInfo { - model_id: string - owner: string - model_type: string - downloaded: boolean -} - -interface LaunchConfig { - model_id: string - address: string - port: number - weight_path?: string | null - save_dir?: string | null - gguf_path?: string | null - mmproj_path?: string | null -} - -interface ServerStatus { - running: boolean - pid: number | null - logs: string[] -} - -export default function LaunchPage() { - const [models, setModels] = useState([]) - const [selectedModel, setSelectedModel] = useState("") - const [address, setAddress] = useState("127.0.0.1") - const [port, setPort] = useState("10100") - const [weightPath, setWeightPath] = useState("") - const [status, setStatus] = useState({ running: false, pid: null, logs: [] }) - const logEndRef = useRef(null) - - // 加载模型列表 - useEffect(() => { - invoke("list_models").then(setModels).catch(() => {}) - }, []) - - // 获取服务状态 - const refreshStatus = useCallback(async () => { - try { - const s = await invoke("get_server_status") - setStatus(s) - } catch {} - }, []) - - // 监听日志和状态事件 - useEffect(() => { - const unlistens: (() => void)[] = [] - - listen("server-log", (event) => { - setStatus((prev) => ({ - ...prev, - logs: [...prev.logs.slice(-1999), event.payload], - })) - }).then((fn) => unlistens.push(fn)) - - listen("server-started", () => { - refreshStatus() - }).then((fn) => unlistens.push(fn)) - - listen("server-stopped", () => { - refreshStatus() - }).then((fn) => unlistens.push(fn)) - - return () => unlistens.forEach((fn) => fn()) - }, [refreshStatus]) - - // 初始加载状态 - useEffect(() => { - refreshStatus() - }, [refreshStatus]) - - // 自动滚动到底部 - useEffect(() => { - logEndRef.current?.scrollIntoView({ behavior: "smooth" }) - }, [status.logs]) - - const handleStart = async () => { - if (!selectedModel) return - try { - await invoke("start_server", { - config: { - model_id: selectedModel, - address, - port: parseInt(port) || 10100, - weight_path: weightPath || null, - save_dir: null, - gguf_path: null, - mmproj_path: null, - } satisfies LaunchConfig, - }) - } catch (e) { - setStatus((prev) => ({ - ...prev, - logs: [...prev.logs, `[错误] ${e}`], - })) - } - } - - const handleStop = async () => { - try { - await invoke("stop_server") - } catch (e) { - setStatus((prev) => ({ - ...prev, - logs: [...prev.logs, `[错误] ${e}`], - })) - } - } - - const handleClearLogs = async () => { - try { - await invoke("clear_logs") - setStatus((prev) => ({ ...prev, logs: [] })) - } catch {} - } - - const downloadedModels = models.filter((m) => m.downloaded) - - return ( -
-

- - 启动服务 -

- - {/* 配置区 */} -
-
- {/* 模型选择 */} -
- - - {downloadedModels.length === 0 && ( -

- 没有已下载的模型,请先在"模型列表"页面下载模型 -

- )} -
- -
-
- - setAddress(e.target.value)} - className="w-full h-9 px-3 rounded-md border bg-background text-sm - focus:outline-none focus:ring-2 focus:ring-ring" - disabled={status.running} - /> -
-
- - setPort(e.target.value)} - className="w-full h-9 px-3 rounded-md border bg-background text-sm - focus:outline-none focus:ring-2 focus:ring-ring" - disabled={status.running} - /> -
-
- - {/* 权重路径 */} -
- - setWeightPath(e.target.value)} - placeholder="留空则使用默认路径" - className="w-full h-9 px-3 rounded-md border bg-background text-sm - focus:outline-none focus:ring-2 focus:ring-ring" - disabled={status.running} - /> -
-
- - {/* 状态 + 控制 */} -
-
-
服务状态
-
-
- - {status.running ? "运行中" : "已停止"} -
- {status.pid && ( -
PID: {status.pid}
- )} - {selectedModel && ( -
- 模型: {selectedModel} -
- )} -
-
- -
- {!status.running ? ( - - ) : ( - - )} -
-
-
- - {/* 日志区域 */} -
-
-
- - 日志输出 -
- -
- -
- {status.logs.length === 0 ? ( -
等待日志输出...
- ) : ( -
- {status.logs.map((line, i) => ( -
- {line} -
- ))} -
-
- )} -
-
-
- ) -} diff --git a/aha-ui/src/pages/ModelsPage.tsx b/aha-ui/src/pages/ModelsPage.tsx deleted file mode 100644 index ec8d8de..0000000 --- a/aha-ui/src/pages/ModelsPage.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import { useState, useEffect } from "react" -import { invoke } from "@tauri-apps/api/core" -import { Download, Trash2, RefreshCw, FolderOpen, HardDrive, Package } from "lucide-react" -import { cn } from "../lib/utils" - -interface ModelInfo { - model_id: string - owner: string - model_type: string - downloaded: boolean - size: number | null - size_human: string | null - path: string | null -} - -const typeColors: Record = { - llm: "bg-blue-100 text-blue-800", - vlm: "bg-purple-100 text-purple-800", - ocr: "bg-green-100 text-green-800", - asr: "bg-yellow-100 text-yellow-800", - tts: "bg-pink-100 text-pink-800", - image: "bg-orange-100 text-orange-800", - embedding: "bg-teal-100 text-teal-800", - reranker: "bg-indigo-100 text-indigo-800", -} - -const typeLabels: Record = { - llm: "LLM", - vlm: "VLM", - ocr: "OCR", - asr: "ASR", - tts: "TTS", - image: "图像", - embedding: "嵌入", - reranker: "重排序", -} - -export default function ModelsPage() { - const [models, setModels] = useState([]) - const [loading, setLoading] = useState(true) - const [downloading, setDownloading] = useState(null) - const [error, setError] = useState(null) - - const loadModels = async () => { - setLoading(true) - try { - const data = await invoke("list_models") - setModels(data) - } catch (e) { - setError(String(e)) - } - setLoading(false) - } - - useEffect(() => { - loadModels() - }, []) - - const handleDownload = async (modelId: string) => { - setDownloading(modelId) - setError(null) - try { - await invoke("download_model", { modelId }) - await loadModels() - } catch (e) { - setError(String(e)) - } - setDownloading(null) - } - - const handleDelete = async (modelId: string) => { - if (!confirm(`确定删除模型 ${modelId}?`)) return - try { - await invoke("delete_model", { modelId }) - await loadModels() - } catch (e) { - setError(String(e)) - } - } - - return ( -
-
-

- - 模型列表 -

- -
- - {error && ( -
- {error} -
- )} - -
-
- - - - - - - - - - - - {models.map((m) => ( - - - - - - - - ))} - -
模型 ID类型大小状态操作
-
{m.model_id}
- {m.path && ( -
- - {m.path} -
- )} -
- - {typeLabels[m.model_type] || m.model_type} - - - {m.size_human ? ( - - - {m.size_human} - - ) : ( - "-" - )} - - {m.downloaded ? ( - - - 已下载 - - ) : ( - 未下载 - )} - -
- {!m.downloaded ? ( - - ) : ( - - )} -
-
-
-
-
- ) -}