feat: transition to a fully frontend architecture by removing backend dependencies and updating configuration for local deployment

This commit is contained in:
HouYunFei
2026-06-16 12:56:49 +08:00
parent 8a66524ea7
commit 7f0199da59
36 changed files with 571 additions and 1773 deletions
+9 -9
View File
@@ -5,7 +5,7 @@ import { Cpu } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { selectableModelsByCapability, type AiConfig, type ModelCapability } from "@/stores/use-config-store";
import { modelOptionLabel, modelOptionName, selectableModelsByCapability, type AiConfig, type ModelCapability } from "@/stores/use-config-store";
type ModelPickerProps = {
config: AiConfig;
@@ -52,10 +52,10 @@ export function ModelPicker({ config, value, onChange, capability, className, fu
)}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
title={current || placeholder}
title={current ? modelOptionLabel(config, current) : placeholder}
>
<ModelIcon model={current} />
<span className="canvas-model-picker-text min-w-0 flex-1 truncate text-left">{current || placeholder}</span>
<span className="canvas-model-picker-text min-w-0 flex-1 truncate text-left">{current ? modelOptionLabel(config, current) : placeholder}</span>
</SelectTrigger>
<SelectContent
data-canvas-no-zoom
@@ -69,8 +69,8 @@ export function ModelPicker({ config, value, onChange, capability, className, fu
>
{options.length ? (
options.map((model) => (
<SelectItem key={model} value={model} textValue={model}>
<ModelLabel model={model} />
<SelectItem key={model} value={model} textValue={modelOptionLabel(config, model)}>
<ModelLabel config={config} model={model} />
</SelectItem>
))
) : (
@@ -86,20 +86,20 @@ export function ModelPicker({ config, value, onChange, capability, className, fu
function emptyModelLabel(config: AiConfig, capability?: ModelCapability) {
const label = capability === "image" ? "生图" : capability === "video" ? "视频" : capability === "text" ? "文本" : capability === "audio" ? "音频" : "";
if (capability && config.models.length) return "请先在上方配置可选模型";
return config.models.length ? `暂无匹配的${label}模型` : "请先到配置里拉取模型列表";
return config.models.length ? `暂无匹配的${label}模型` : "请先到配置里添加渠道和模型";
}
function ModelLabel({ model }: { model: string }) {
function ModelLabel({ config, model }: { config: AiConfig; model: string }) {
return (
<span className="flex min-w-0 items-center gap-2">
<ModelIcon model={model} />
<span className="truncate">{model}</span>
<span className="truncate">{modelOptionLabel(config, model)}</span>
</span>
);
}
function ModelIcon({ model }: { model: string }) {
const icon = resolveModelIcon(model);
const icon = resolveModelIcon(modelOptionName(model));
return icon ? <img src={icon} alt="" className="size-4 shrink-0 dark:invert" /> : <Cpu className="size-4 shrink-0 opacity-70" />;
}