import { AudioLines, Check, Film, Flame, Image, MessageSquareText, Network, Settings2, Sparkles } from "lucide-react";
import { Button, Modal } from "antd";
import { useEffect, useState, type ReactNode } from "react";
import { ModelIcon } from "@/components/model-picker";
import { MODEL_PROTOCOLS, modelProtocolLabel, type ModelProtocol, type ModelProtocolDefinition, type ProtocolCapability } from "@/lib/model-protocols";
import { cn } from "@/lib/utils";
export type ModelCapabilityChoice = ProtocolCapability;
const capabilityChoices: Array<{
value: ModelCapabilityChoice;
label: string;
description: string;
icon: ReactNode;
brands: string[];
}> = [
{ value: "text", label: "文本", description: "对话与推理", icon: , brands: ["openai", "deepseek", "glm"] },
{ value: "image", label: "图片", description: "生成与编辑", icon: , brands: ["openai", "gemini"] },
{ value: "video", label: "视频", description: "生成与续写", icon: , brands: ["grok", "gemini"] },
{ value: "audio", label: "音频", description: "语音与音效", icon: , brands: ["openai"] },
];
type PickerDensity = "comfortable" | "compact";
export function CapabilityCardPicker({ value, onChange, density = "comfortable" }: { value?: ModelCapabilityChoice; onChange?: (value: ModelCapabilityChoice) => void; density?: PickerDensity }) {
return (
{capabilityChoices.map((item) => {
const selected = value === item.value;
return (
);
})}
);
}
export function ProtocolCardPicker({ capability, value, onChange, density = "comfortable" }: { capability?: ModelCapabilityChoice; value?: ModelProtocol; onChange?: (value: ModelProtocol) => void; density?: PickerDensity }) {
const protocols = MODEL_PROTOCOLS.filter((item) => item.capability === capability);
return (
{protocols.map((protocol) => {
const selected = value === protocol.value;
return (
);
})}
);
}
export function ModelCapabilityProtocolModal({ value, onChange }: { value: { capability: ModelCapabilityChoice; protocol: ModelProtocol }; onChange: (value: { capability: ModelCapabilityChoice; protocol: ModelProtocol }) => void }) {
const [open, setOpen] = useState(false);
const [draft, setDraft] = useState(value);
useEffect(() => {
if (!open) setDraft(value);
}, [open, value]);
const updateCapability = (capability: ModelCapabilityChoice) => {
const protocol = draft.protocol && MODEL_PROTOCOLS.some((item) => item.value === draft.protocol && item.capability === capability)
? draft.protocol
: MODEL_PROTOCOLS.find((item) => item.capability === capability)?.value || "chat-completion";
setDraft({ capability, protocol });
};
return (
<>
} onClick={() => { setDraft(value); setOpen(true); }}>
{capabilityLabel(value.capability)} · {modelProtocolLabel(value.protocol)}
setOpen(false)}
okText="应用配置"
cancelText="取消"
onOk={() => { onChange(draft); setOpen(false); }}
>
请求协议
setDraft((current) => ({ ...current, protocol }))} />
>
);
}
function ProtocolBrandMark({ protocol, compact = false }: { protocol: ModelProtocolDefinition; compact?: boolean }) {
const iconSize = compact ? "size-6" : "size-8";
if (protocol.value === "chat-completion") return ;
if (protocol.value.startsWith("volcengine-jimeng-")) return ;
if (protocol.value.startsWith("volcengine-")) return ;
if (protocol.value.startsWith("newapi-channel-") || protocol.value === "novita-video") return ;
const brand = protocol.value === "gemini-veo" ? "gemini" : protocol.value === "grok-image" || protocol.value === "xai-video" ? "grok" : "openai";
return ;
}
function BrandIconRow({ models, compact = false, className }: { models: string[]; compact?: boolean; className?: string }) {
return (
{models.map((model) => )}
);
}
function modelBrandLabel(model: string) {
const labels: Record = { openai: "OpenAI", deepseek: "DeepSeek", glm: "智谱 GLM", gemini: "Google Gemini", grok: "xAI Grok" };
return labels[model] || model;
}
function capabilityLabel(value: ModelCapabilityChoice) {
return { text: "文本", image: "图片", video: "视频", audio: "音频" }[value];
}