= ({ endpointType, onEndpointChange, className }) => {
return (
Endpoint Type:
diff --git a/ui/litellm-dashboard/src/components/chat_ui/chatUtils.test.ts b/ui/litellm-dashboard/src/components/chat_ui/chatUtils.test.ts
new file mode 100644
index 0000000000..547bc72e81
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/chat_ui/chatUtils.test.ts
@@ -0,0 +1,14 @@
+import { describe, expect, it } from "vitest";
+import { truncateString } from "./chatUtils";
+
+describe("chatUtils", () => {
+ describe("truncateString", () => {
+ it("should truncate a string", () => {
+ expect(truncateString("Hello, world!", 5)).toBe("Hello...");
+ });
+
+ it("should return the original string if it is less than the max length", () => {
+ expect(truncateString("Hello, world!", 20)).toBe("Hello, world!");
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/chat_ui/chatUtils.ts b/ui/litellm-dashboard/src/components/chat_ui/chatUtils.ts
new file mode 100644
index 0000000000..bd590a5ae1
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/chat_ui/chatUtils.ts
@@ -0,0 +1,3 @@
+export function truncateString(str: string, maxLength: number) {
+ return str.length > maxLength ? str.substring(0, maxLength) + "..." : str;
+}
diff --git a/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.test.tsx b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.test.tsx
new file mode 100644
index 0000000000..c8d4d49cbe
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.test.tsx
@@ -0,0 +1,59 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { makeOpenAIEmbeddingsRequest } from "./embeddings_api";
+import OpenAI from "openai";
+
+vi.mock("openai");
+
+describe("embeddings_api", () => {
+ const mockCreate = vi.fn();
+ const mockUpdateEmbeddingsUI = vi.fn();
+
+ beforeEach(() => {
+ // Mock the response structure from OpenAI embeddings API
+ mockCreate.mockResolvedValue({
+ data: [
+ {
+ embedding: [0.1, 0.2, 0.3, 0.4, 0.5],
+ index: 0,
+ object: "embedding",
+ },
+ ],
+ model: "text-embedding-3-small",
+ object: "list",
+ usage: {
+ prompt_tokens: 5,
+ total_tokens: 5,
+ },
+ });
+
+ // Mock the OpenAI constructor and its methods
+ (OpenAI as any).mockImplementation(() => ({
+ embeddings: {
+ create: mockCreate,
+ },
+ }));
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should make a request to the embeddings API", async () => {
+ await makeOpenAIEmbeddingsRequest(
+ "Hello, world!",
+ mockUpdateEmbeddingsUI,
+ "text-embedding-3-small",
+ "1234567890",
+ [],
+ );
+
+ expect(mockCreate).toHaveBeenCalledWith({
+ model: "text-embedding-3-small",
+ input: "Hello, world!",
+ });
+ expect(mockUpdateEmbeddingsUI).toHaveBeenCalledWith(
+ JSON.stringify([0.1, 0.2, 0.3, 0.4, 0.5]),
+ "text-embedding-3-small",
+ );
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.tsx b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.tsx
new file mode 100644
index 0000000000..7a5ab21d9f
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/embeddings_api.tsx
@@ -0,0 +1,50 @@
+import NotificationManager from "@/components/molecules/notifications_manager";
+import { getProxyBaseUrl } from "@/components/networking";
+import openai from "openai";
+
+export async function makeOpenAIEmbeddingsRequest(
+ input: string,
+ updateEmbeddingsUI: (embeddings: string, model?: string) => void,
+ selectedModel: string,
+ accessToken: string,
+ tags?: string[],
+) {
+ if (!accessToken) {
+ throw new Error("API key is required");
+ }
+
+ // Base URL should be the current base_url
+ const isLocal = process.env.NODE_ENV === "development";
+ if (isLocal !== true) {
+ console.log = function () {};
+ }
+
+ const proxyBaseUrl = getProxyBaseUrl();
+ // Prepare headers with tags and trace ID
+ const headers: Record = {};
+ if (tags && tags.length > 0) {
+ headers["x-litellm-tags"] = tags.join(",");
+ }
+
+ const client = new openai.OpenAI({
+ apiKey: accessToken,
+ baseURL: proxyBaseUrl,
+ dangerouslyAllowBrowser: true,
+ defaultHeaders: headers,
+ });
+
+ try {
+ const response = await client.embeddings.create({
+ model: selectedModel,
+ input: input,
+ });
+
+ updateEmbeddingsUI(JSON.stringify(response.data[0].embedding), selectedModel);
+ } catch (error: unknown) {
+ NotificationManager.fromBackend(
+ `Error occurred while making embeddings request. Please try again. Error: ${error}`,
+ );
+
+ throw error; // Re-throw to allow the caller to handle the error
+ }
+}
diff --git a/ui/litellm-dashboard/src/components/chat_ui/mode_endpoint_mapping.tsx b/ui/litellm-dashboard/src/components/chat_ui/mode_endpoint_mapping.tsx
index 65b4c0b867..ef798c367c 100644
--- a/ui/litellm-dashboard/src/components/chat_ui/mode_endpoint_mapping.tsx
+++ b/ui/litellm-dashboard/src/components/chat_ui/mode_endpoint_mapping.tsx
@@ -17,6 +17,7 @@ export enum EndpointType {
RESPONSES = "responses",
IMAGE_EDITS = "image_edits",
ANTHROPIC_MESSAGES = "anthropic_messages",
+ EMBEDDINGS = "embeddings",
// add additional endpoint types if required
}