mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-25 08:32:11 +03:00
@@ -1051,7 +1051,7 @@ export default function ProviderDetailPage() {
|
|||||||
name: cm.name || cm.id,
|
name: cm.name || cm.id,
|
||||||
source: cm.source === "api-sync" ? "api-sync" : "custom",
|
source: cm.source === "api-sync" ? "api-sync" : "custom",
|
||||||
}));
|
}));
|
||||||
return [...builtInModels, ...syncedExtras, ...customExtras];
|
return [...builtInModels, ...syncedExtras];
|
||||||
}, [providerId, registryModels, syncedAvailableModels, modelMeta.customModels]);
|
}, [providerId, registryModels, syncedAvailableModels, modelMeta.customModels]);
|
||||||
const providerAlias = getProviderAlias(providerId);
|
const providerAlias = getProviderAlias(providerId);
|
||||||
const isManagedAvailableModelsProvider = isCompatible || providerId === "openrouter";
|
const isManagedAvailableModelsProvider = isCompatible || providerId === "openrouter";
|
||||||
@@ -2680,11 +2680,7 @@ export default function ProviderDetailPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button size="sm" icon="add" onClick={() => setShowAddApiKeyModal(true)}>
|
||||||
size="sm"
|
|
||||||
icon="add"
|
|
||||||
onClick={() => setShowAddApiKeyModal(true)}
|
|
||||||
>
|
|
||||||
{t("add")}
|
{t("add")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -3076,15 +3072,13 @@ export default function ProviderDetailPage() {
|
|||||||
{renderModelsSection()}
|
{renderModelsSection()}
|
||||||
|
|
||||||
{/* Custom Models — available for all providers */}
|
{/* Custom Models — available for all providers */}
|
||||||
{!isManagedAvailableModelsProvider && (
|
<CustomModelsSection
|
||||||
<CustomModelsSection
|
providerId={providerId}
|
||||||
providerId={providerId}
|
providerAlias={providerDisplayAlias}
|
||||||
providerAlias={providerDisplayAlias}
|
copied={copied}
|
||||||
copied={copied}
|
onCopy={copy}
|
||||||
onCopy={copy}
|
onModelsChanged={fetchProviderModelMeta}
|
||||||
onModelsChanged={fetchProviderModelMeta}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -3875,6 +3869,7 @@ function CustomModelsSection({
|
|||||||
const [editingApiFormat, setEditingApiFormat] = useState("chat-completions");
|
const [editingApiFormat, setEditingApiFormat] = useState("chat-completions");
|
||||||
const [editingEndpoints, setEditingEndpoints] = useState<string[]>(["chat"]);
|
const [editingEndpoints, setEditingEndpoints] = useState<string[]>(["chat"]);
|
||||||
const [savingModelId, setSavingModelId] = useState<string | null>(null);
|
const [savingModelId, setSavingModelId] = useState<string | null>(null);
|
||||||
|
const [togglingModelId, setTogglingModelId] = useState<string | null>(null);
|
||||||
|
|
||||||
const customMap = useMemo(() => buildCompatMap(customModels), [customModels]);
|
const customMap = useMemo(() => buildCompatMap(customModels), [customModels]);
|
||||||
const overrideMap = useMemo(() => buildCompatMap(modelCompatOverrides), [modelCompatOverrides]);
|
const overrideMap = useMemo(() => buildCompatMap(modelCompatOverrides), [modelCompatOverrides]);
|
||||||
@@ -3943,6 +3938,28 @@ function CustomModelsSection({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleHidden = async (modelId: string, hidden: boolean) => {
|
||||||
|
setTogglingModelId(modelId);
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
`/api/provider-models?provider=${encodeURIComponent(providerId)}&modelId=${encodeURIComponent(modelId)}`,
|
||||||
|
{
|
||||||
|
method: "PATCH",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ isHidden: hidden }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.ok) {
|
||||||
|
await fetchCustomModels();
|
||||||
|
onModelsChanged?.();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to toggle model visibility:", e);
|
||||||
|
} finally {
|
||||||
|
setTogglingModelId(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const beginEdit = (model) => {
|
const beginEdit = (model) => {
|
||||||
setEditingModelId(model.id);
|
setEditingModelId(model.id);
|
||||||
setEditingApiFormat(model.apiFormat || "chat-completions");
|
setEditingApiFormat(model.apiFormat || "chat-completions");
|
||||||
@@ -4311,6 +4328,16 @@ function CustomModelsSection({
|
|||||||
showDeveloperToggle
|
showDeveloperToggle
|
||||||
disabled={savingModelId === model.id}
|
disabled={savingModelId === model.id}
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => handleToggleHidden(model.id, !model.isHidden)}
|
||||||
|
disabled={togglingModelId === model.id}
|
||||||
|
className="rounded p-1 text-text-muted hover:bg-sidebar hover:text-primary disabled:opacity-50"
|
||||||
|
title={model.isHidden ? t("unhideModel") : t("hideModel")}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined text-sm">
|
||||||
|
{model.isHidden ? "visibility_off" : "visibility"}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleRemove(model.id)}
|
onClick={() => handleRemove(model.id)}
|
||||||
className="rounded p-1 text-red-500 hover:bg-red-50"
|
className="rounded p-1 text-red-500 hover:bg-red-50"
|
||||||
|
|||||||
@@ -545,7 +545,15 @@ export default function ProxyRegistryManager() {
|
|||||||
title={editingId ? t("modalEditTitle") : t("modalCreateTitle")}
|
title={editingId ? t("modalEditTitle") : t("modalCreateTitle")}
|
||||||
maxWidth="lg"
|
maxWidth="lg"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-3">
|
<form
|
||||||
|
className="flex flex-col gap-3"
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSave();
|
||||||
|
}}
|
||||||
|
autoComplete="off"
|
||||||
|
data-1p-ignore="true"
|
||||||
|
>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-text-muted mb-1 block">{t("labelName")}</label>
|
<label className="text-xs text-text-muted mb-1 block">{t("labelName")}</label>
|
||||||
@@ -643,7 +651,7 @@ export default function ProxyRegistryManager() {
|
|||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -105,12 +105,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const existingConnections = await getProviderConnections({ provider });
|
const existingConnections = await getProviderConnections({ provider });
|
||||||
if (!allowMultipleCompatibleConnections && existingConnections.length > 0) {
|
// Allow multiple connections for compatible nodes exactly like first-party providers
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Only one connection is allowed for this OpenAI Compatible node" },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
providerSpecificData = {
|
providerSpecificData = {
|
||||||
...(providerSpecificData || {}),
|
...(providerSpecificData || {}),
|
||||||
@@ -135,12 +130,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const existingConnections = await getProviderConnections({ provider });
|
const existingConnections = await getProviderConnections({ provider });
|
||||||
if (!allowMultipleCompatibleConnections && existingConnections.length > 0) {
|
// Allow multiple connections for compatible nodes exactly like first-party providers
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Only one connection is allowed for this Anthropic Compatible node" },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
providerSpecificData = {
|
providerSpecificData = {
|
||||||
...(providerSpecificData || {}),
|
...(providerSpecificData || {}),
|
||||||
|
|||||||
Reference in New Issue
Block a user