Files
bifrost/ui/app/workspace/logs/views/emptyState.tsx
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

323 lines
9.8 KiB
TypeScript

import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { CodeEditor } from "@/components/ui/codeEditor";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useCopyToClipboard } from "@/hooks/useCopyToClipboard";
import { getExampleBaseUrl } from "@/lib/utils/port";
import { AlertTriangle, Copy } from "lucide-react";
import { useMemo, useState } from "react";
type Provider = "openai" | "anthropic" | "genai" | "litellm" | "langchain";
type Language = "python" | "typescript";
type Examples = {
curl: string;
sdk: {
[P in Provider]: {
[L in Language]: string;
};
};
};
// Common editor options to reduce duplication
const EditorOptions = {
scrollBeyondLastLine: false,
minimap: { enabled: false },
lineNumbers: "off",
folding: false,
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
glyphMargin: false,
} as const;
interface CodeBlockProps {
code: string;
language: string;
onLanguageChange?: (language: string) => void;
showLanguageSelect?: boolean;
readonly?: boolean;
}
function CodeBlock({ code, language, onLanguageChange, showLanguageSelect = false, readonly = true }: CodeBlockProps) {
const { copy: copyToClipboard } = useCopyToClipboard();
return (
<div className="relative">
<div className="absolute top-4 right-4 z-10 flex items-center gap-2">
{showLanguageSelect && onLanguageChange && (
<Select value={language} onValueChange={onLanguageChange}>
<SelectTrigger className="h-8 w-fit text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem className="text-xs" value="python">
Python
</SelectItem>
<SelectItem className="text-xs" value="typescript">
TypeScript
</SelectItem>
</SelectContent>
</Select>
)}
<Button variant="ghost" size="icon" onClick={() => copyToClipboard(code)}>
<Copy className="size-4" />
</Button>
</div>
<CodeEditor className="w-full" code={code} lang={language} readonly={readonly} height={300} fontSize={14} options={EditorOptions} />
</div>
);
}
interface EmptyStateProps {
error: string | null;
}
export function EmptyState({ error }: EmptyStateProps) {
const [language, setLanguage] = useState<Language>("python");
// Generate examples dynamically using the port utility
const examples: Examples = useMemo(() => {
const baseUrl = getExampleBaseUrl();
return {
curl: `curl -X POST ${baseUrl}/v1/chat/completions \\
-H "Content-Type: application/json" \\
-d '{
"model": "openai/gpt-4o-mini",
"messages": [
{"role": "user", "content": "Hello!"}
]
}'`,
sdk: {
openai: {
python: `import openai
client = openai.OpenAI(
base_url="${baseUrl}/openai",
api_key="dummy-api-key" # Handled by Bifrost
)
response = client.chat.completions.create(
model="gpt-4o-mini", # or "provider/model" for other providers (anthropic/claude-3-sonnet)
messages=[{"role": "user", "content": "Hello!"}]
)`,
typescript: `import OpenAI from "openai";
const openai = new OpenAI({
baseURL: "${baseUrl}/openai",
apiKey: "dummy-api-key", // Handled by Bifrost
});
const response = await openai.chat.completions.create({
model: "gpt-4o-mini", // or "provider/model" for other providers (anthropic/claude-3-sonnet)
messages: [{ role: "user", content: "Hello!" }],
});`,
},
anthropic: {
python: `import anthropic
client = anthropic.Anthropic(
base_url="${baseUrl}/anthropic",
api_key="dummy-api-key" # Handled by Bifrost
)
response = client.messages.create(
model="claude-3-sonnet-20240229", # or "provider/model" for other providers (openai/gpt-4o-mini)
max_tokens=1000,
messages=[{"role": "user", "content": "Hello!"}]
)`,
typescript: `import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({
baseURL: "${baseUrl}/anthropic",
apiKey: "dummy-api-key", // Handled by Bifrost
});
const response = await anthropic.messages.create({
model: "claude-3-sonnet-20240229", // or "provider/model" for other providers (openai/gpt-4o-mini)
max_tokens: 1000,
messages: [{ role: "user", content: "Hello!" }],
});`,
},
genai: {
python: `from google import genai
from google.genai.types import HttpOptions
client = genai.Client(
api_key="dummy-api-key", # Handled by Bifrost
http_options=HttpOptions(base_url="${baseUrl}/genai")
)
response = client.models.generate_content(
model="gemini-2.5-pro", # or "provider/model" for other providers (openai/gpt-4o-mini)
contents="Hello!"
)`,
typescript: `import { GoogleGenerativeAI } from "@google/generative-ai";
const genAI = new GoogleGenerativeAI("dummy-api-key", { // Handled by Bifrost
baseUrl: "${baseUrl}/genai",
});
const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); // or "provider/model" for other providers (openai/gpt-4o-mini)
const response = await model.generateContent("Hello!");`,
},
litellm: {
python: `import litellm
litellm.api_base = "${baseUrl}/litellm"
response = litellm.completion(
model="openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Hello!"}]
)`,
typescript: `import { completion } from "litellm";
const response = await completion({
model: "openai/gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
api_base: "${baseUrl}/litellm",
});`,
},
langchain: {
python: `from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Initialize ChatOpenAI with Bifrost
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="dummy-api-key", # Handled by Bifrost
base_url="${baseUrl}/langchain",
max_tokens=100,
)
# Simple message
messages = [HumanMessage(content="Hello from LangChain!")]
response = llm.invoke(messages)
# Chain with prompt template
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("human", "{input}")
])
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"input": "What is LangChain?"})`,
typescript: `import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
// Initialize ChatOpenAI with Bifrost
const llm = new ChatOpenAI({
model: "gpt-4o-mini",
openAIApiKey: "dummy-api-key", // Handled by Bifrost
clientOptions: {
baseURL: "${baseUrl}/langchain",
},
maxTokens: 100,
});
// Simple message
const messages = [new HumanMessage("Hello from LangChain!")];
const response = await llm.invoke(messages);
// Chain with prompt template
const prompt = ChatPromptTemplate.fromMessages([
["system", "You are a helpful assistant."],
["human", "{input}"],
]);
const chain = prompt.pipe(llm).pipe(new StringOutputParser());
const result = await chain.invoke({ input: "What is LangChain?" });`,
},
},
};
}, []);
const isUnexpectedError = error && error.includes("An unexpected error occurred");
return (
<div className="dark:bg-card flex w-full flex-col items-center justify-center space-y-8 bg-white">
{error && (
<Alert>
<AlertTriangle className="h-4 w-4" />
<AlertDescription>
{isUnexpectedError ? "Looks like you haven't configured the log store in your config file." : error}
</AlertDescription>
</Alert>
)}
<div className="w-full space-y-6 p-4">
<div className="flex flex-row items-center gap-2">
<div>
<h3 className="text-lg font-semibold">Integrate under 60 seconds</h3>
<p className="text-muted-foreground text-sm">Send your first request to get started</p>
</div>
</div>
<Tabs defaultValue="curl" className="w-full rounded-lg border">
<TabsList className="grid h-10 w-full grid-cols-6 rounded-t-lg rounded-b-none">
<TabsTrigger value="curl">cURL</TabsTrigger>
<TabsTrigger value="openai">OpenAI SDK</TabsTrigger>
<TabsTrigger value="anthropic">Anthropic SDK</TabsTrigger>
<TabsTrigger value="genai">Google GenAI SDK</TabsTrigger>
<TabsTrigger value="litellm">LiteLLM SDK</TabsTrigger>
<TabsTrigger value="langchain">LangChain SDK</TabsTrigger>
</TabsList>
<TabsContent value="curl" className="px-4">
<CodeBlock code={examples.curl} language="bash" readonly={false} />
</TabsContent>
<TabsContent value="openai" className="px-4">
<CodeBlock
code={examples.sdk.openai[language]}
language={language}
onLanguageChange={(newLang) => setLanguage(newLang as Language)}
showLanguageSelect
/>
</TabsContent>
<TabsContent value="anthropic" className="px-4">
<CodeBlock
code={examples.sdk.anthropic[language]}
language={language}
onLanguageChange={(newLang) => setLanguage(newLang as Language)}
showLanguageSelect
/>
</TabsContent>
<TabsContent value="genai" className="px-4">
<CodeBlock
code={examples.sdk.genai[language]}
language={language}
onLanguageChange={(newLang) => setLanguage(newLang as Language)}
showLanguageSelect
/>
</TabsContent>
<TabsContent value="litellm" className="px-4">
<CodeBlock
code={examples.sdk.litellm[language]}
language={language}
onLanguageChange={(newLang) => setLanguage(newLang as Language)}
showLanguageSelect
/>
</TabsContent>
<TabsContent value="langchain" className="px-4">
<CodeBlock
code={examples.sdk.langchain[language]}
language={language}
onLanguageChange={(newLang) => setLanguage(newLang as Language)}
showLanguageSelect
/>
</TabsContent>
</Tabs>
</div>
</div>
);
}