Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "https://www.getbifrost.ai/schema",
"version": 2,
"providers": {
"openai": {
"keys": [
{
"value": "env.OPENAI_API_KEY"
}
]
}
}
}
294 changes: 153 additions & 141 deletions docs/providers/performance.mdx

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions ui/app/__error.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Button } from "@/components/ui/button";
import { useTranslation } from "react-i18next";

export function ErrorComponent() {
const { t } = useTranslation();
return (
<main className="h-base flex items-center justify-center p-6">
<div className="mx-auto w-full max-w-md text-center">
<p className="text-foreground text-7xl font-bold tracking-tight">500</p>
<h1 className="text-foreground mt-4 text-2xl font-semibold">Something went wrong</h1>
<p className="text-muted-foreground mt-2 text-sm">Something went wrong. Please refresh the page.</p>
<h1 className="text-foreground mt-4 text-2xl font-semibold">{t("error.title")}</h1>
<p className="text-muted-foreground mt-2 text-sm">{t("error.description")}</p>
<div className="mt-6 flex items-center justify-center gap-3">
<Button size={"sm"} data-testid="error-reload-btn" onClick={() => window.location.reload()}>
Reload
{t("common.reload")}
</Button>
</div>
</div>
Expand Down
8 changes: 5 additions & 3 deletions ui/app/__notFound.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { Link } from "@tanstack/react-router";
import { useTranslation } from "react-i18next";

export function NotFoundComponent() {
const { t } = useTranslation();
return (
<main className="h-base flex items-center justify-center p-6">
<div className="mx-auto w-full max-w-md text-center">
<p className="text-foreground text-7xl font-bold tracking-tight">404</p>
<h1 className="text-foreground mt-4 text-2xl font-semibold">Page not found</h1>
<p className="text-muted-foreground mt-2 text-sm">The page you are looking for doesn’t exist or has been moved</p>
<h1 className="text-foreground mt-4 text-2xl font-semibold">{t("notFound.title")}</h1>
<p className="text-muted-foreground mt-2 text-sm">{t("notFound.description")}</p>
<div className="mt-6 flex items-center justify-center gap-3">
<Link
data-testid="not-found-go-home-link"
to="/workspace/logs"
className="bg-primary text-primary-foreground focus-visible:ring-primary inline-flex items-center rounded-md px-4 py-2 text-sm font-medium shadow transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
>
Go home
{t("common.goHome")}
</Link>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { ShieldCheck } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function AccessProfilesIndexView() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<ShieldCheck className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock access profiles for better performance"
description="This feature is a part of the Bifrost enterprise license. Create access profiles to control access to your resources."
title={t("workspace.accessProfiles.unlockTitle")}
description={t("workspace.accessProfiles.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/access-profiles"
testIdPrefix="access-profiles"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Shuffle } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function AdaptiveRoutingView() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<Shuffle className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock adaptive routing for better performance"
description="This feature is a part of the Bifrost enterprise license. We would love to know more about your use case and how we can help you."
title={t("workspace.adaptiveRouting.unlockTitle")}
description={t("workspace.adaptiveRouting.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/adaptive-load-balancing"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { useCopyToClipboard } from "@/hooks/useCopyToClipboard";
import { Link } from "@tanstack/react-router";
import { Copy, InfoIcon, KeyRound } from "lucide-react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function APIKeysView() {
const { t } = useTranslation();
const { data: bifrostConfig, isLoading } = useGetCoreConfigQuery({ fromDB: true });
const isAuthConfigure = useMemo(() => {
return bifrostConfig?.auth_config?.is_enabled;
Expand All @@ -32,21 +34,21 @@ curl --location 'http://localhost:8080/v1/chat/completions'
const { copy: copyToClipboard } = useCopyToClipboard();

if (isLoading) {
return <div>Loading...</div>;
return <div>{t("common.loading")}</div>;
}
if (!isAuthConfigure) {
return (
<Alert variant="default">
<InfoIcon className="text-muted h-4 w-4" />
<AlertDescription>
<p className="text-md text-muted-foreground">
To generate API keys, you need to set up admin username and password first.{" "}
{t("workspace.config.apiKeys.authRequiredPrefix")}{" "}
<Link to="/workspace/config/security" className="text-md text-primary underline">
Configure Security Settings
{t("workspace.config.apiKeys.configureSecuritySettings")}
</Link>
.<br />
<br />
Once generated you will need to use this API key for all API calls to the Bifrost admin APIs and UI.
{t("workspace.config.apiKeys.authRequiredSuffix")}
</p>
</AlertDescription>
</Alert>
Expand All @@ -63,22 +65,25 @@ curl --location 'http://localhost:8080/v1/chat/completions'
<p className="text-md text-muted-foreground">
{isInferenceAuthDisabled ? (
<>
Authentication is currently <strong>disabled for inference API calls</strong>. You can make inference requests without
authentication. Dashboard and admin API calls still require Basic auth with your admin credentials encoded in the standard{" "}
<code className="bg-muted rounded px-1 py-0.5 text-sm">username:password</code> format with base64 encoding.
{t("workspace.config.apiKeys.inferenceAuthDisabledPrefix")}{" "}
<strong>{t("workspace.config.apiKeys.disabledForInferenceCalls")}</strong>.{" "}
{t("workspace.config.apiKeys.inferenceAuthDisabledSuffix")}{" "}
<code className="bg-muted rounded px-1 py-0.5 text-sm">username:password</code>{" "}
{t("workspace.config.apiKeys.basicAuthEncodingSuffix")}
</>
) : (
<>
Use Basic auth with your admin credentials when making API calls to Bifrost. Encode your credentials in the standard{" "}
<code className="bg-muted rounded px-1 py-0.5 text-sm">username:password</code> format with base64 encoding.
{t("workspace.config.apiKeys.basicAuthNoticePrefix")}{" "}
<code className="bg-muted rounded px-1 py-0.5 text-sm">username:password</code>{" "}
{t("workspace.config.apiKeys.basicAuthEncodingSuffix")}
</>
)}
</p>
{!isInferenceAuthDisabled && (
<>
<br />
<p className="text-md text-muted-foreground">
<strong>Example:</strong>
<strong>{t("workspace.config.apiKeys.example")}</strong>
</p>

<div className="relative mt-2 w-full min-w-0 overflow-x-auto">
Expand All @@ -95,8 +100,8 @@ curl --location 'http://localhost:8080/v1/chat/completions'
<ContactUsView
className="mt-4 rounded-md border px-3 py-8"
icon={<KeyRound size={48} />}
title="Scope Based API Keys"
description="Need granular access control with scope-based API keys? Enterprise customers can create multiple API keys with specific permissions for different services, teams, or environments."
title={t("workspace.config.apiKeys.scopeBasedApiKeys")}
description={t("workspace.config.apiKeys.scopeBasedApiKeysDesc")}
readmeLink="https://docs.getbifrost.io/enterprise/api-keys"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { ScrollText } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function AuditLogsView() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<ScrollText className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock audit logs for better compliance"
description="This feature is a part of the Bifrost enterprise license. We would love to know more about your use case and how we can help you."
title={t("workspace.auditLogs.unlockTitle")}
description={t("workspace.auditLogs.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/audit-logs"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Layers } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function ClusterPage() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<Layers className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock cluster mode to scale reliably"
description="This feature is a part of the Bifrost enterprise license. We would love to know more about your use case and how we can help you."
title={t("workspace.cluster.unlockTitle")}
description={t("workspace.cluster.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/clustering"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Construction } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function GuardrailsConfigurationView() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<Construction className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock guardrails for better security"
description="This feature is a part of the Bifrost enterprise license. We would love to know more about your use case and how we can help you."
title={t("workspace.guardrailsConfiguration.unlockTitle")}
description={t("workspace.guardrailsConfiguration.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/guardrails"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Construction } from "lucide-react";
import { useTranslation } from "react-i18next";
import ContactUsView from "../views/contactUsView";

export default function guardrailsProviderView() {
const { t } = useTranslation();

return (
<div className="h-full w-full">
<ContactUsView
className="mx-auto min-h-[80vh]"
icon={<Construction className="h-[5.5rem] w-[5.5rem]" strokeWidth={1} />}
title="Unlock guardrails for better security"
description="This feature is a part of the Bifrost enterprise license. We would love to know more about your use case and how we can help you."
title={t("workspace.guardrailsProviders.unlockTitle")}
description={t("workspace.guardrailsProviders.unlockDescription")}
readmeLink="https://docs.getbifrost.ai/enterprise/guardrails"
/>
</div>
Expand Down
28 changes: 15 additions & 13 deletions ui/app/_fallbacks/enterprise/components/login/loginView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,29 @@ import { useNavigate } from "@tanstack/react-router";
import { Eye, EyeOff } from "lucide-react";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

const externalLinks = [
{
title: "Discord Server",
titleKey: "sidebar.external.discord",
url: "https://discord.gg/exN5KAydbU",
icon: DiscordLogoIcon,
},
{
title: "GitHub Repository",
titleKey: "sidebar.external.github",
url: "https://github.com/maximhq/bifrost",
icon: GithubLogoIcon,
},
{
title: "Full Documentation",
titleKey: "sidebar.external.fullDocs",
url: "https://docs.getbifrost.ai",
icon: BooksIcon,
strokeWidth: 1,
},
];

export default function LoginView() {
const { t } = useTranslation();
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
const [username, setUsername] = useState("");
Expand All @@ -52,7 +54,7 @@ export default function LoginView() {
return;
}
if (isAuthEnabledError) {
setErrorMessage("Unable to verify authentication status. Please retry.");
setErrorMessage(t("login.authError"));
return;
}
if (!isAuthEnabled || hasValidToken) {
Expand Down Expand Up @@ -92,7 +94,7 @@ export default function LoginView() {
<img src={logoSrc} alt="Bifrost" width={160} height={26} className="" />
</div>
<div className="flex items-center justify-center py-8">
<div className="text-muted-foreground text-sm">Checking authentication...</div>
<div className="text-muted-foreground text-sm">{t("login.checkingAuth")}</div>
</div>
</div>
</div>
Expand All @@ -110,21 +112,21 @@ export default function LoginView() {
</div>

<div className="space-y-2 text-center">
<h1 className="text-foreground text-lg font-semibold">Welcome back</h1>
<p className="text-muted-foreground text-sm">Sign in to your account to continue</p>
<h1 className="text-foreground text-lg font-semibold">{t("login.welcome")}</h1>
<p className="text-muted-foreground text-sm">{t("login.subtitle")}</p>
</div>

<form onSubmit={handleSubmit} className="space-y-5">
{errorMessage && <div className="bg-destructive/10 text-destructive rounded-sm p-3 text-sm">{errorMessage}</div>}

<div className="space-y-2">
<Label htmlFor="username" className="text-sm font-medium">
Username
{t("login.username")}
</Label>
<Input
id="username"
type="text"
placeholder="Enter your username"
placeholder={t("login.enterUsername")}
value={username}
onChange={(e) => setUsername(e.target.value)}
required
Expand All @@ -135,13 +137,13 @@ export default function LoginView() {

<div className="space-y-2">
<Label htmlFor="password" className="text-sm font-medium">
Password
{t("login.password")}
</Label>
<div className="relative">
<Input
id="password"
type={showPassword ? "text" : "password"}
placeholder="Enter your password"
placeholder={t("login.enterPassword")}
value={password}
onChange={(e) => setPassword(e.target.value)}
required
Expand All @@ -160,7 +162,7 @@ export default function LoginView() {
</div>

<Button type="submit" className="h-9 w-full text-sm" isLoading={isLoading} disabled={isLoading}>
{isLoading || isLoggingIn ? "Signing in..." : "Sign in"}
{isLoading || isLoggingIn ? t("login.signingIn") : t("login.signIn")}
</Button>
</form>

Expand All @@ -173,7 +175,7 @@ export default function LoginView() {
target="_blank"
rel="noopener noreferrer"
className="text-muted-foreground hover:text-primary transition-colors"
title={item.title}
title={t(item.titleKey)}
>
<item.icon className="h-5 w-5" size={20} weight="regular" strokeWidth={item.strokeWidth} />
</a>
Expand Down
Loading