Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DOC] New Chroma Docs #3315

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
[DOC] New Chroma docs
itaismith committed Dec 16, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit b4c1e785925652aa97f32b67b0d97c2071151c8f
2 changes: 1 addition & 1 deletion docs/docs.trychroma.com/README.md
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ It also incldues [Shadcn](https://ui.shadcn.com/) with [Tailwind](https://tailwi
- Dark/Light Mode
- Responsive
- Global and Local state management with localstorage persistence
- Tabs
- MarkdocTabs
- Code styling with Prism
- Toasts

20 changes: 20 additions & 0 deletions docs/docs.trychroma.com/app/[...slug]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import Sidebar from "@/components/sidebar/sidebar";

interface LayoutProps {
children: React.ReactNode;
params: { slug: string[] };
}

const PageLayout: React.FC<LayoutProps> = ({ children, params }) => {
const { slug } = params;

return (
<div className="flex flex-grow overflow-hidden">
<Sidebar path={slug} />
<div className="flex-grow overflow-y-auto">{children}</div>
</div>
);
};

export default PageLayout;
19 changes: 19 additions & 0 deletions docs/docs.trychroma.com/app/[...slug]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import CodeBlock from "@/components/markdoc/code-block";

const notFoundCode = `
import chromadb
client = chromadb.Client()
collection = client.get_collection(name="chroma_docs")
results = collection.get(ids=["page"])["documents"]
print(results) # Not found []
`

const NotFound = () => {
return <div className="flex items-center justify-center w-full h-full">
<CodeBlock className="p-4 bg-gray-800 text-white" content={notFoundCode} language="python" showHeader={true}/>
</div>
}

export default NotFound;
11 changes: 11 additions & 0 deletions docs/docs.trychroma.com/app/[...slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react";
import MarkdocRenderer from "@/components/markdoc/markdoc-renderer";

// TODO: Add page metadata for SEO

const Page: React.FC<{ params: { slug: string[] } }> = ({ params }) => {
const { slug } = params;
return <MarkdocRenderer slug={slug} />;
};

export default Page;
File renamed without changes.
Binary file not shown.
Binary file added docs/docs.trychroma.com/app/fonts/GeistVF.woff
Binary file not shown.
20 changes: 20 additions & 0 deletions docs/docs.trychroma.com/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
font-family: Arial, Helvetica, sans-serif;
@apply text-[#27201C] dark:text-white
}

@layer utilities {
.text-balance {
text-wrap: balance;
}
}

@layer base {
:root {
--radius: 0.5rem;
}
}
43 changes: 43 additions & 0 deletions docs/docs.trychroma.com/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Metadata } from "next";
import "./globals.css";
import React from "react";
import ThemeProvider from "@/components/ui/theme-provider";
import { Inter } from "next/font/google";
import Header from "@/components/header/header";
import PostHogProvider from "@/components/posthog/posthog-provider";

export const metadata: Metadata = {
title: "Chroma Docs",
description: "Documentation for ChromaDB",
};

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="h-full overscroll-none" suppressHydrationWarning>
<body className={`h-full overflow-hidden ${inter.className} antialiased`}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<PostHogProvider>
<div className="relative h-full w-full">
<div className="absolute inset-0 bg-[url('/background.jpg')] bg-cover bg-center opacity-10 dark:invert dark:opacity-10" />
<div className="relative z-10 flex flex-col h-full">
<Header />
{children}
</div>
</div>
</PostHogProvider>
</ThemeProvider>
</body>
</html>
);
}
19 changes: 19 additions & 0 deletions docs/docs.trychroma.com/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import CodeBlock from "@/components/markdoc/code-block";

const notFoundCode = `
import chromadb
client = chromadb.Client()
collection = client.get_collection(name="chroma_docs")
results = collection.get(ids=["page"])["documents"]
print(results) # Not found []
`

const NotFound = () => {
return <div className="flex items-center justify-center w-full h-full">
<CodeBlock className="p-4 bg-gray-800 text-white" content={notFoundCode} language="python" showHeader={true}/>
</div>
}

export default NotFound;
5 changes: 5 additions & 0 deletions docs/docs.trychroma.com/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from "next/navigation";

export default function Home() {
return redirect("/docs/overview/introduction");
}
19 changes: 11 additions & 8 deletions docs/docs.trychroma.com/components.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "public/globals.css",
"baseColor": "slate",
"cssVariables": true,
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "zinc",
"cssVariables": false,
"prefix": ""
},
"aliases": {
"components": "components",
"utils": "lib/utils"
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
}
194 changes: 0 additions & 194 deletions docs/docs.trychroma.com/components/CodeBlock.tsx

This file was deleted.

49 changes: 0 additions & 49 deletions docs/docs.trychroma.com/components/CopyToClipboardButton.tsx

This file was deleted.

29 changes: 29 additions & 0 deletions docs/docs.trychroma.com/components/header/discord-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import Link from "next/link";
import UIButton from "@/components/ui/ui-button";
import { DiscordLogoIcon } from "@radix-ui/react-icons";

const DiscordLink: React.FC = async () => {
const response = await fetch(
`https://discord.com/api/guilds/1073293645303795742/widget.json`,
{ next: { revalidate: 3600 } },
);
const onlineUsers = response.ok
? (await response.json()).presence_count
: undefined;

return (
<Link
href="https://discord.gg/MMeYNTmh3x"
target="_blank"
rel="noopener noreferrer"
>
<UIButton className="flex items-center gap-2 p-[0.35rem] text-xs">
<DiscordLogoIcon className="h-4 w-4" />
{onlineUsers ? `${onlineUsers} online` : undefined}
</UIButton>
</Link>
);
};

export default DiscordLink;
29 changes: 29 additions & 0 deletions docs/docs.trychroma.com/components/header/github-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import UIButton from "@/components/ui/ui-button";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import { formatToK } from "@/lib/utils";
import Link from "next/link";

const GithubLink: React.FC = async () => {
const response = await fetch(
`https://api.github.com/repos/chroma-core/chroma`,
);
const stars = response.ok
? (await response.json()).stargazers_count
: undefined;

return (
<Link
href="https://github.com/chroma-core/chroma"
target="_blank"
rel="noopener noreferrer"
>
<UIButton className="flex items-center gap-2 p-[0.35rem] text-xs">
<GitHubLogoIcon className="h-4 w-4" />
{stars && formatToK(stars)}
</UIButton>
</Link>
);
};

export default GithubLink;
29 changes: 29 additions & 0 deletions docs/docs.trychroma.com/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import Logo from "@/components/header/logo";
import ThemeToggle from "@/components/header/theme-toggle";
import GithubLink from "@/components/header/github-link";
import XLink from "@/components/header/x-link";
import DiscordLink from "@/components/header/discord-link";
import Link from "next/link";
import SearchBox from "@/components/header/search-box";

const Header: React.FC = () => {
return (
<div className="flex items-center justify-between flex-shrink-0 p-3 px-5 h-14 border-b-[1px] dark:border-gray-700 xl:w-[1256px] xl:mx-auto">
<div className="flex items-center gap-5">
<Link href="/">
<Logo />
</Link>
<SearchBox />
</div>
<div className="flex items-center justify-between gap-2">
<DiscordLink />
<GithubLink />
<XLink />
<ThemeToggle />
</div>
</div>
);
};

export default Header;
41 changes: 41 additions & 0 deletions docs/docs.trychroma.com/components/header/language-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";

import React, { useState } from "react";
import PythonLogo from "../../public/python.svg";
import TypeScriptLogo from "../../public/typescript.svg";
import UIButton from "@/components/ui/ui-button";

const supportedLanguages: {
[language: string]: React.FC<React.SVGProps<SVGSVGElement>>;
} = {
python: PythonLogo,
typescript: TypeScriptLogo,
};

const LanguageToggle: React.FC = () => {
const [preferredLanguage, setPreferredLanguage] = useState<string>("python");

const switchLanguage = (language: string) => {
setPreferredLanguage(language);
};

return (
<div className="flex items-center gap-2">
{Object.keys(supportedLanguages).map((language) => {
const Logo = supportedLanguages[language];
const selected = preferredLanguage === language;
return (
<UIButton
key={`${language}-button`}
className={`p-[0.35rem] ${!selected && "grayscale"}`}
onClick={switchLanguage.bind(null, language)}
>
<Logo className="h-4 w-4" />
</UIButton>
);
})}
</div>
);
};

export default LanguageToggle;
16 changes: 16 additions & 0 deletions docs/docs.trychroma.com/components/header/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import ChromaLogo from "../../public/chroma-workmark-color-128.svg";
import OutlineLogo from "../../public/chroma-wordmark-white-128.svg";

const Logo: React.FC = () => {
const logoClass = "w-28 h-10";

return (
<div className="relative">
<ChromaLogo className={`${logoClass} dark:hidden`} />
<OutlineLogo className={`${logoClass} hidden dark:inline-block`} />
</div>
);
};

export default Logo;
18 changes: 18 additions & 0 deletions docs/docs.trychroma.com/components/header/search-box.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import React from "react";
import { DocSearch } from "@docsearch/react";
import "@docsearch/css";

const SearchBox: React.FC = () => {
return (
<DocSearch
appId={process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!}
apiKey={process.env.NEXT_PUBLIC_ALGOLIA_API_KEY!}
indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME!}
insights
/>
);
};

export default SearchBox;
21 changes: 21 additions & 0 deletions docs/docs.trychroma.com/components/header/sidebar-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
import Sidebar from "@/components/sidebar/sidebar";
import { SidebarIcon } from "lucide-react";

const SidebarToggle: React.FC<{ path: string[] }> = ({ path }) => {
return (
<Drawer direction="left">
<DrawerTrigger>
<div className="absolute -top-7 -left-14 md:hidden">
<SidebarIcon children="w-5 h-5" />
</div>
</DrawerTrigger>
<DrawerContent className="h-full w-[270px]">
<Sidebar path={path} mobile />
</DrawerContent>
</Drawer>
);
};

export default SidebarToggle;
29 changes: 29 additions & 0 deletions docs/docs.trychroma.com/components/header/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";

import * as React from "react";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";

import UIButton from "@/components/ui/ui-button";

const ThemeToggle = () => {
const { theme, setTheme } = useTheme();

const toggleTheme = () => {
if (theme === "dark") {
setTheme("light");
} else {
setTheme("dark");
}
};

return (
<UIButton onClick={toggleTheme} className="p-[0.35rem]">
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</UIButton>
);
};

export default ThemeToggle;
21 changes: 21 additions & 0 deletions docs/docs.trychroma.com/components/header/x-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import Link from "next/link";
import UIButton from "@/components/ui/ui-button";
import XLogo from "../../public/x-logo.svg";

const XLink: React.FC = () => {
return (
<Link
href="https://x.com/trychroma"
target="_blank"
rel="noopener noreferrer"
>
<UIButton className="flex items-center gap-2 p-[0.35rem] text-xs">
<XLogo className="h-[14px] w-[14px] invert dark:invert-0" />
<p>17.7k</p>
</UIButton>
</Link>
);
};

export default XLink;
142 changes: 0 additions & 142 deletions docs/docs.trychroma.com/components/layout/SideNav.tsx

This file was deleted.

65 changes: 0 additions & 65 deletions docs/docs.trychroma.com/components/layout/TableOfContents.tsx

This file was deleted.

43 changes: 0 additions & 43 deletions docs/docs.trychroma.com/components/layout/TopNav.tsx

This file was deleted.

42 changes: 0 additions & 42 deletions docs/docs.trychroma.com/components/layout/state.tsx

This file was deleted.

10 changes: 0 additions & 10 deletions docs/docs.trychroma.com/components/markdoc/AppLink.tsx

This file was deleted.

12 changes: 0 additions & 12 deletions docs/docs.trychroma.com/components/markdoc/CodeTab.tsx

This file was deleted.

36 changes: 0 additions & 36 deletions docs/docs.trychroma.com/components/markdoc/CodeTabs.tsx

This file was deleted.

67 changes: 0 additions & 67 deletions docs/docs.trychroma.com/components/markdoc/Heading.tsx

This file was deleted.

8 changes: 0 additions & 8 deletions docs/docs.trychroma.com/components/markdoc/Math.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions docs/docs.trychroma.com/components/markdoc/Note.tsx

This file was deleted.

3 changes: 0 additions & 3 deletions docs/docs.trychroma.com/components/markdoc/SpecialTable.tsx

This file was deleted.

12 changes: 0 additions & 12 deletions docs/docs.trychroma.com/components/markdoc/Tab.tsx

This file was deleted.

62 changes: 0 additions & 62 deletions docs/docs.trychroma.com/components/markdoc/Tabs.tsx

This file was deleted.

26 changes: 26 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { InfoCircledIcon } from "@radix-ui/react-icons";

const Banner: React.FC<{ type: string; children: React.ReactNode }> = ({
type,
children,
}) => {
const styles: Record<string, string> = {
note: "bg-yellow-500",
tip: "bg-blue-500",
warn: "bg-red-500 ",
};

return (
<div className="my-7">
<div className="relative border-[1px] px-7 border-gray-900 bg-white dark:bg-black dark:border-gray-600">
<div
className={`absolute top-1.5 left-1.5 w-full h-full -z-10 ${styles[type]}`}
/>
{children}
</div>
</div>
);
};

export default Banner;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

const CenteredContent: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
return <div className="flex items-center justify-center">{children}</div>;
};

export default CenteredContent;
24 changes: 24 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/code-block-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import { Playfair_Display } from "next/font/google";
import CopyButton from "@/components/markdoc/copy-button";
import { capitalize } from "@/lib/utils";

export const tabLabelStyle = `rounded-none px-4 py-2 text-xs font-medium tracking-wider border-b-[1px] border-transparent disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-transparent data-[state=active]:text-chroma-orange data-[state=active]:shadow-none data-[state=active]:border-chroma-orange cursor-pointer select-none font-mono tracking-tight`;

const CodeBlockHeader: React.FC<{
language: string;
content: string;
}> = ({ language, content }) => {
return (
<div className="flex items-center justify-between bg-gray-900 rounded-t-sm">
<div className={tabLabelStyle} data-state={"active"}>
{capitalize(language)}
</div>
<div className="flex items-center pr-3">
<CopyButton content={content} />
</div>
</div>
);
};

export default CodeBlockHeader;
58 changes: 58 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/code-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import { unified } from "unified";
import parse from "remark-parse";
import rehypeHighlight from "rehype-highlight";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import { visit } from "unist-util-visit";
import CodeBlockHeader from "@/components/markdoc/code-block-header";

import "highlight.js/styles/atom-one-dark.css";

const rehypeRemovePre = () => {
return (tree: any) => {
visit(tree, "element", (node) => {
if (node.tagName === "pre" && node.children.length) {
const codeNode = node.children.find(
(child: { tagName: string }) => child.tagName === "code",
);
if (codeNode) {
node.tagName = "code";
node.children = codeNode.children;
}
}
});
};
};

const CodeBlock: React.FC<{
content: React.ReactNode;
language: string;
showHeader: boolean;
className?: string;
}> = async ({ content, language, showHeader = true, className }) => {
if (typeof content !== "string") {
throw new Error("CodeBlock children must be a string.");
}

const highlightedCode = await unified()
.use(parse)
.use(remarkRehype)
.use(rehypeHighlight, { subset: [language] })
.use(rehypeRemovePre)
.use(rehypeStringify)
.process(`\`\`\`${language}\n${content}\`\`\``);

return (
<div className="flex flex-col mb-2">
{showHeader && language && (
<CodeBlockHeader language={language} content={content} />
)}
<pre className={`rounded-none rounded-b-sm m-0 ${className}`}>
<div dangerouslySetInnerHTML={{ __html: highlightedCode.toString() }} />
</pre>
</div>
);
};

export default CodeBlock;
16 changes: 16 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/code-tab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import React, { useContext } from "react";
import AppContext from "@/context/app-context";
import { Tabs } from "@/components/ui/tabs";

const CodeTabs: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { language } = useContext(AppContext);
return (
<Tabs defaultValue="python" value={language} className="flex flex-col mt-5">
{children}
</Tabs>
);
};

export default CodeTabs;
47 changes: 47 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/copy-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use client";

import React, { useState } from "react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { CopyIcon } from "lucide-react";

const CopyButton: React.FC<{ content: string }> = ({ content }) => {
const [copied, setCopied] = useState<boolean>(false);
const [open, setOpen] = useState<boolean>(false);

const handleCopy = () => {
navigator.clipboard.writeText(content).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
};

return (
<TooltipProvider delayDuration={350}>
<Tooltip open={open}>
<TooltipTrigger
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
>
<CopyIcon
onClick={handleCopy}
className="w-4 h-4 text-gray-400 hover:text-gray-200 cursor-pointer"
/>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={10}
className="flex items-center justify-center"
>
<p className="text-xs">{copied ? "Copied!" : "Copy"}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};

export default CopyButton;
11 changes: 11 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/inline-code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react";

const InlineCode: React.FC<{ content: React.ReactNode }> = ({ content }) => {
return (
<span className="inline-flex items-center justify-center py-[1px] px-1.5 bg-slate-100 dark:bg-gray-800 rounded-md text-orange-600 text-sm font-medium font-mono border-[1px] border-gray-200 dark:border-gray-600">
{content}
</span>
);
};

export default InlineCode;
23 changes: 23 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/latex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import katex from 'katex';
import 'katex/dist/katex.min.css';

const Latex:React.FC<{children: React.ReactNode}> = ({children}) => {
const content = React.Children.toArray(children).join('');
try {
return (
<span
dangerouslySetInnerHTML={{
__html: katex.renderToString(content, {
throwOnError: false,
}),
}}
/>
);
} catch (error) {
console.error(error);
return <span style={{ color: 'red' }}>Error rendering LaTeX</span>;
}
}

export default Latex;
38 changes: 38 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/markdoc-heading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";

const generateId = (content: React.ReactNode): string => {
if (typeof content === "string") {
return content
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.trim();
}
return "";
};

const Heading: React.FC<{
level: number;
children: React.ReactNode;
id?: string;
}> = ({ level, children, id }) => {
const HeadingTag: React.ElementType = `h${level}` as React.ElementType;
const headingId = id || generateId(children);

return (
<HeadingTag id={headingId} className={`group`}>
{children}
{headingId && level === 2 && (
<a
href={`#${headingId}`}
className="ml-2 opacity-0 group-hover:opacity-100 transition-opacity"
aria-label={`Link to ${headingId}`}
>
#
</a>
)}
</HeadingTag>
);
};

export default Heading;
17 changes: 17 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/markdoc-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import Image from "next/image";
import { imageSize } from "image-size";

const MarkdocImage: React.FC<{ src: string; alt: string; title?: string }> = ({
src,
alt,
}) => {
try {
const { width, height } = imageSize(`public/${src}`);
return <Image src={src} alt={alt} width={width} height={height} priority />;
} catch (e) {
return <div />;
}
};

export default MarkdocImage;
16 changes: 16 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/markdoc-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import React from "react";
import { AppContextProvider } from "@/context/app-context";

const MarkdocPage: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return (
<AppContextProvider>
<div className="w-full max-w-full h-full overflow-y-scroll py-10 pb-40 px-14 pl-20 prose dark:prose-invert xl:pr-[calc((100vw-1256px)/2)]">
<div>{children}</div>
</div>
</AppContextProvider>
);
};

export default MarkdocPage;
64 changes: 64 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/markdoc-renderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import fs from "fs";
import path from "path";
import React from "react";
import Markdoc from "@markdoc/markdoc";
import markdocConfig from "@/markdoc/config";
import { notFound } from "next/navigation";
import MarkdocPage from "@/components/markdoc/markdoc-page";
import SidebarToggle from "@/components/header/sidebar-toggle";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import Link from "next/link";
import { getAllPages, getPagePrevNext } from "@/lib/content";
import sidebarConfig from "@/markdoc/content/sidebar-config";
import PageNav from "@/components/markdoc/page-nav";

const MarkdocRenderer: React.FC<{ slug: string[] }> = ({ slug }) => {
const filePath = `${path.join(process.cwd(), "markdoc", "content", ...slug)}.md`;

if (!fs.existsSync(filePath)) {
notFound();
}

const source = fs.readFileSync(filePath, "utf-8");

const ast = Markdoc.parse(source);
const content = Markdoc.transform(ast, markdocConfig);

const output = Markdoc.renderers.react(content, React, {
components: markdocConfig.components,
});

const GitHubLink = `https://github.com/chroma-core/chroma/tree/main/docs/docs.trychroma.com/markdoc/content/${slug.join("/")}.md`;

const { prev, next } = getPagePrevNext(
slug,
getAllPages(sidebarConfig, slug[0]),
);

return (
<MarkdocPage>
<div className="relative w-full h-full marker:text-black dark:marker:text-gray-200">
<SidebarToggle path={slug} />
{output}
<div className="flex items-center justify-between mt-5">
{prev ? (
<PageNav path={prev.path || ""} name={prev.name} type="prev" />
) : (
<div />
)}
{next ? (
<PageNav path={next.path || ""} name={next.name} type="next" />
) : (
<div />
)}
</div>
<div className="flex items-center gap-2 mt-5">
<GitHubLogoIcon className="w-5 h-5" />
<Link href={GitHubLink}>Edit this page on GitHub</Link>
</div>
</div>
</MarkdocPage>
);
};

export default MarkdocRenderer;
100 changes: 100 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/markdoc-tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use client";

import React, { ReactElement, useContext, useRef } from "react";
import {
Tabs as UITabs,
TabsContent,
TabsList,
TabsTrigger as UITabsTrigger,
} from "@/components/ui/tabs";
import { capitalize, cn } from "@/lib/utils";
import { tabLabelStyle } from "@/components/markdoc/code-block-header";
import AppContext from "@/context/app-context";
import CodeBlock from "@/components/markdoc/code-block";
import { Playfair_Display } from "next/font/google";

export const playfairDisplay = Playfair_Display({
subsets: ["latin"],
display: "swap",
weight: "500",
variable: "--font-playfair-display",
});

export interface TabProps {
label: string;
children: React.ReactElement<{ content: string; showHeader: boolean }>;
}

export const TabsTrigger = React.forwardRef<
React.ElementRef<typeof UITabsTrigger>,
React.ComponentPropsWithoutRef<typeof UITabsTrigger>
>(({ value, ...props }, ref) => {
const { setLanguage } = useContext(AppContext);
const triggerRef = useRef<HTMLButtonElement | null>(null);

return (
<UITabsTrigger
ref={triggerRef}
value={value}
{...props}
onClick={() => {
setLanguage(value);
}}
/>
);
});
TabsTrigger.displayName = "TabsTrigger";

const Tab: React.FC<TabProps> = ({ children }) => {
return <div>{children}</div>;
};

export const MarkdocTabs: React.FC<{ children: ReactElement<TabProps>[] }> = ({
children,
}) => {
const { language } = useContext(AppContext);
return (
<div className="my-4 p-2 px-3 border-[1px] border-dashed border-gray-300 dark:border-gray-700">
<UITabs
defaultValue={children[0].props.label}
value={language}
className="flex flex-col mt-2 pb-2"
>
<TabsList className="justify-start bg-transparent dark:bg-transparent rounded-none p-0 h-fit border-b border-gray-300 mb-4 dark:border-gray-700">
{children.map((tab) => (
<TabsTrigger
key={`${tab.props.label}-header`}
value={tab.props.label}
className={cn(
tabLabelStyle,
playfairDisplay.className,
"text-sm tracking-normal dark:data-[state=active]:bg-transparent data-[state=active]:border-b data-[state=active]:text-gray-900 dark:data-[state=active]:text-gray-200 data-[state=active]:border-gray-900 dark:data-[state=active]:border-gray-200",
)}
>
{capitalize(tab.props.label)}
</TabsTrigger>
))}
</TabsList>
<div>
{children.map((tab) => (
<TabsContent
key={`${tab.props.label}-content`}
value={tab.props.label}
className="m-0"
>
{tab.props.children.type === CodeBlock
? React.cloneElement(tab, {
children: React.cloneElement(tab.props.children, {
showHeader: false,
}),
})
: tab}
</TabsContent>
))}
</div>
</UITabs>
</div>
);
};

export default Tab;
3 changes: 0 additions & 3 deletions docs/docs.trychroma.com/components/markdoc/misc.tsx

This file was deleted.

37 changes: 37 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/page-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import React from "react";
import Link from "next/link";
import { ArrowLeft, ArrowRight } from "lucide-react";

const PageNav: React.FC<{
path: string;
name: string;
type: "prev" | "next";
}> = ({ path, name, type }) => {
return (
<Link
href={path}
onClick={() => {
sessionStorage.removeItem("sidebarScrollPosition");
}}
>
<div className="flex items-center gap-2">
{type === "prev" && (
<>
<ArrowLeft className="w-4 h-4" />
<p>{name}</p>
</>
)}
{type === "next" && (
<>
<p>{name}</p>
<ArrowRight className="w-4 h-4" />
</>
)}
</div>
</Link>
);
};

export default PageNav;
69 changes: 69 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/tabbed-code-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { ReactElement } from "react";
import CopyButton from "@/components/markdoc/copy-button";
import { TabsContent, TabsList } from "@/components/ui/tabs";
import { tabLabelStyle } from "@/components/markdoc/code-block-header";
import { capitalize, cn } from "@/lib/utils";
import CodeBlock from "@/components/markdoc/code-block";
import { TabProps, TabsTrigger } from "@/components/markdoc/markdoc-tabs";
import CodeTabs from "@/components/markdoc/code-tab";

const TabbedCodeBlock: React.FC<{
children: ReactElement<TabProps>[];
}> = ({ children }) => {
const tabs = children.map((tab) => {
return {
label: tab.props.label,
content: tab.props.children.props.content,
render:
tab.props.children.type === CodeBlock
? React.cloneElement(tab, {
children: React.cloneElement(tab.props.children, {
showHeader: false,
}),
})
: tab,
};
});

return (
<CodeTabs>
<div className="flex items-center justify-between bg-gray-900 rounded-t-sm">
<TabsList className="bg-transparent dark:bg-transparent rounded-none p-0 h-fit m-0">
{tabs.map((tab) => (
<TabsTrigger
key={`${tab.label}-header`}
value={tab.label}
className={cn(tabLabelStyle)}
>
{capitalize(tab.label)}
</TabsTrigger>
))}
</TabsList>
<div className="flex items-center pr-3">
{tabs.map((tab) => (
<TabsContent
key={`${tab.label}-copy`}
value={tab.label}
className="flex items-center m-0"
>
<CopyButton content={tab.content || ""} />
</TabsContent>
))}
</div>
</div>
<div>
{tabs.map((tab) => (
<TabsContent
key={`${tab.label}-content`}
value={tab.label}
className="m-0"
>
{tab.render}
</TabsContent>
))}
</div>
</CodeTabs>
);
};

export default TabbedCodeBlock;
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { ReactElement } from "react";
import { tabLabelStyle } from "@/components/markdoc/code-block-header";
import { capitalize, cn } from "@/lib/utils";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { TabProps } from "@/components/markdoc/markdoc-tabs";
import CodeBlock from "@/components/markdoc/code-block";
import CopyButton from "@/components/markdoc/copy-button";

const TabbedUseCaseCodeBlock: React.FC<{
language: string;
children: ReactElement<TabProps>[];
}> = ({ language, children }) => {
return (
<Tabs defaultValue={children[0].props.label} className="flex flex-col">
<div className="flex items-center justify-between bg-gray-900 rounded-t-sm">
<div className="flex items-center gap-7">
<div className={tabLabelStyle} data-state={"active"}>
{capitalize(language)}
</div>
<TabsList className="bg-transparent dark:bg-transparent rounded-none p-0 h-fit">
{children.map((tab) => (
<TabsTrigger
key={`${tab.props.label}-header`}
value={tab.props.label}
className={cn(
tabLabelStyle,
"data-[state=active]:text-gray-200 data-[state=active]:border-gray-200 dark:data-[state=active]:bg-transparent",
)}
>
{tab.props.label}
</TabsTrigger>
))}
</TabsList>
</div>
<div className="flex items-center pr-3">
{children.map((tab) => (
<TabsContent
key={`${tab.props.label}-copy`}
value={tab.props.label}
className="flex items-center m-0"
>
<CopyButton content={tab.props.children.props.content || ""} />
</TabsContent>
))}
</div>
</div>
<div>
{children.map((tab) => (
<TabsContent
key={`${tab.props.label}-content`}
value={tab.props.label}
className="m-0"
>
{tab.props.children.type === CodeBlock
? React.cloneElement(tab, {
children: React.cloneElement(tab.props.children, {
showHeader: false,
}),
})
: tab}
</TabsContent>
))}
</div>
</Tabs>
);
};

export default TabbedUseCaseCodeBlock;
59 changes: 59 additions & 0 deletions docs/docs.trychroma.com/components/markdoc/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
Table as UITable,
TableHeader as UITableHeader,
TableBody as UITableBody,
TableRow as UITableRow,
TableHead as UITableHead,
TableCell as UITableCell,
} from "@/components/ui/table";
import React from "react";

export const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ ...props }, ref) => {
return (
<div className="relative w-full overflow-auto rounded-md my-5 border-[0.5px] border-gray-300">
<UITable ref={ref} className="m-0" {...props} />
</div>
);
});
Table.displayName = "Table";

export const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ ...props }, ref) => (
<UITableHeader ref={ref} className="border-none bg-gray-900" {...props} />
));
TableHeader.displayName = "TableHeader";

export const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ ...props }, ref) => <UITableBody ref={ref} {...props} />);
TableBody.displayName = "TableBody";

export const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ ...props }, ref) => <UITableRow ref={ref} className="" {...props} />);
TableRow.displayName = "TableRow";

export const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ ...props }, ref) => (
<UITableHead
ref={ref}
className="text-gray-200 dark:text-gray-200 py-1"
{...props}
/>
));
TableHead.displayName = "TableHead";

export const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ ...props }, ref) => <UITableCell className="" ref={ref} {...props} />);
TableCell.displayName = "TableCell";
34 changes: 34 additions & 0 deletions docs/docs.trychroma.com/components/posthog/posthog-pageview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import { usePathname, useSearchParams } from "next/navigation";
import React, { useEffect, Suspense } from "react";
import { usePostHog } from "posthog-js/react";

export const PostHogPageView: React.FC = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
const posthog = usePostHog();

useEffect(() => {
if (pathname && posthog) {
let url = window.origin + pathname;
if (searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}

posthog.capture("$pageview", { $current_url: url });
}
}, [pathname, searchParams, posthog]);

return null;
};

const SuspendedPostHogPageView: React.FC = () => {
return (
<Suspense fallback={null}>
<PostHogPageView />
</Suspense>
);
};

export default SuspendedPostHogPageView;
27 changes: 27 additions & 0 deletions docs/docs.trychroma.com/components/posthog/posthog-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import posthog from "posthog-js";
import { PostHogProvider as PHProvider } from "posthog-js/react";
import React, { useEffect } from "react";
import SuspendedPostHogPageView from "@/components/posthog/posthog-pageview";

const PostHogProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
useEffect(() => {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
person_profiles: "identified_only",
capture_pageview: false,
});
}, []);

return (
<PHProvider client={posthog}>
<SuspendedPostHogPageView />
{children}
</PHProvider>
);
};

export default PostHogProvider;
42 changes: 42 additions & 0 deletions docs/docs.trychroma.com/components/sidebar/menu-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import Link from "next/link";
import { AppSection } from "@/lib/content";

const MenuItem: React.FC<{ section: AppSection; active: boolean }> = ({
section,
active,
}) => {
const Icon = section.icon!;

return (
<Link
href={
section.comingSoon
? ""
: `/${section.id}/${section.default || (section.pages ? section.pages[0].id : "")}`
}
>
<div
className={`flex items-center gap-2 text-gray-700/80 cursor-pointer ${!section.comingSoon && "hover:text-gray-800"} dark:text-gray-400/80 dark:hover:text-gray-300`}
>
<div
className={`flex items-center justify-center p-1.5 rounded-lg ${active && "border border-chroma-orange bg-chroma-orange/10 text-chroma-orange"}`}
>
<Icon className="w-5 h-5" />
</div>
<p
className={`font-semibold select-none ${active && "text-chroma-orange"}`}
>
{section.name}
</p>
{section.comingSoon && (
<div className="inline-flex text-xs px-2 py-0.5 bg-gray-800 rounded-md text-gray-200">
Coming Soon
</div>
)}
</div>
</Link>
);
};

export default MenuItem;
39 changes: 39 additions & 0 deletions docs/docs.trychroma.com/components/sidebar/page-index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import { Playfair_Display } from "next/font/google";
import PageLink from "@/components/sidebar/page-link";

const playfairDisplay = Playfair_Display({
subsets: ["latin"],
display: "swap",
weight: "500",
variable: "--font-playfair-display",
});

const PageIndex: React.FC<{
path: string;
pages: { id: string; name: string }[];
name?: string;
}> = ({ path, pages, name }) => {
return (
<div className="select-none cursor-pointer">
{name && (
<p className={`${playfairDisplay.className} mb-2 tracking-wide`}>
{name}
</p>
)}
<div className="flex flex-col">
{pages.map((page) => (
<PageLink
key={page.id}
id={page.id}
name={page.name}
path={`${path}/${page.id}`}
sectionPage={name !== undefined}
/>
))}
</div>
</div>
);
};

export default PageIndex;
30 changes: 30 additions & 0 deletions docs/docs.trychroma.com/components/sidebar/page-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client";

import React from "react";
import Link from "next/link";
import { usePathname, useSearchParams } from "next/navigation";

const PageLink: React.FC<{
id: string;
name: string;
path: string;
sectionPage: boolean;
}> = ({ id, name, path, sectionPage = true }) => {
const pathName = usePathname();
const searchParams = useSearchParams();
const active = pathName === path;
const lang = searchParams.get("lang");

return (
<div
key={id}
className={`${sectionPage ? "pl-7" : "pl-3"} py-0.5 border-l border-gray-300 hover:border-gray-900 dark:border-gray-500 dark:hover:border-gray-200 ${active && "border-gray-900 dark:border-white font-bold"}`}
>
<Link href={lang ? `${path}?lang=${lang}` : path}>
<p className="text-sm">{name}</p>
</Link>
</div>
);
};

export default PageLink;
69 changes: 69 additions & 0 deletions docs/docs.trychroma.com/components/sidebar/scrollable-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";

import React, { useEffect, useRef } from "react";
import { usePathname } from "next/navigation";

const ScrollableContent: React.FC<{
pagesIndex: string[];
children: React.ReactNode;
}> = ({ pagesIndex, children }) => {
const pathname = usePathname();
const scrollRef = useRef<HTMLDivElement>(null);

const handleScroll = () => {
if (scrollRef.current) {
sessionStorage.setItem(
"sidebarScrollPosition",
scrollRef.current.scrollTop.toString(),
);
}
};

useEffect(() => {
const sectionScrollPosition = (userPath: string[]) => {
const userPage = userPath[userPath.length - 1];
const currentPage = pagesIndex.find((p) => p === userPage);
if (!currentPage) return 0;
return pagesIndex.indexOf(currentPage) * 25;
};

if (!scrollRef.current) return;

const userPath = pathname.slice(1).split("/");
const section = userPath[0];

const storedScrollPosition = sessionStorage.getItem(
"sidebarScrollPosition",
);

const storedSection = sessionStorage.getItem("sidebarSection");

if (!storedSection) {
sessionStorage.setItem("sidebarSection", section);
} else if (storedSection !== section) {
sessionStorage.setItem("sidebarSection", section);
sessionStorage.removeItem("sidebarScrollPosition");
}

if (storedScrollPosition) {
scrollRef.current.scrollTop = parseInt(storedScrollPosition, 10);
} else {
scrollRef.current.scrollTop = sectionScrollPosition(userPath);
}

const ref = scrollRef.current;
ref.addEventListener("scroll", handleScroll);
return () => ref.removeEventListener("scroll", handleScroll);
}, [pathname, pagesIndex]);

return (
<div
ref={scrollRef}
className="flex flex-col flex-grow overflow-scroll pb-10 pr-5"
>
<div className="flex flex-col gap-5">{children}</div>
</div>
);
};

export default ScrollableContent;
91 changes: 91 additions & 0 deletions docs/docs.trychroma.com/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from "react";
import MenuItem from "@/components/sidebar/menu-item";
import sidebarConfig from "@/markdoc/content/sidebar-config";
import PageIndex from "@/components/sidebar/page-index";
import path from "path";
import fs from "fs";
import matter from "gray-matter";
import ScrollableContent from "./scrollable-content";

const generatePages = (slug: string[]): { id: string; name: string }[] => {
const dirPath = path.join(process.cwd(), "markdoc", "content", ...slug);
const files = fs.readdirSync(dirPath);

const pages = [];

for (const file of files) {
if (file.endsWith(".md")) {
const filePath = path.join(dirPath, file);
const content = fs.readFileSync(filePath, "utf-8");

const { data } = matter(content);
if (data.id && data.name) {
pages.push({ id: data.id, name: data.name });
}
}
}

return pages;
};

const Sidebar: React.FC<{ path: string[]; mobile?: boolean }> = ({
path,
mobile,
}) => {
const currentSection = sidebarConfig.find((section) =>
path.join("").startsWith(section.id),
);

if (!currentSection) {
return null;
}

const allSectionPages: string[] = [
...(currentSection.pages || []).map((p) => p.id),
];
currentSection.subsections?.forEach((subsection) => {
allSectionPages.push(...(subsection.pages?.map((p) => p.id) || []));
});

return (
<div
className={`h-full xl:ml-[calc((100vw-1256px)/2)] ${!mobile && "hidden md:block"}`}
>
<div className="flex flex-col h-full w-64 p-5 border-r-[1px] flex-shrink-0 dark:border-gray-700">
<div className="flex flex-col gap-1 pb-10">
{sidebarConfig.map((section) => (
<MenuItem
key={section.id}
section={section}
active={currentSection.id === section.id}
/>
))}
</div>
<ScrollableContent pagesIndex={allSectionPages}>
{currentSection.pages && (
<div className="flex flex-col gap-2">
<PageIndex
path={`/${currentSection.id}`}
pages={currentSection.pages}
/>
</div>
)}
{currentSection.subsections?.map((subsection) => (
<PageIndex
key={subsection.id}
name={subsection.name}
path={`/${currentSection.id}/${subsection.id}`}
pages={
subsection.generatePages
? generatePages([currentSection.id, subsection.id])
: subsection.pages || []
}
/>
))}
</ScrollableContent>
</div>
</div>
);
};

export default Sidebar;
36 changes: 36 additions & 0 deletions docs/docs.trychroma.com/components/ui/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const badgeVariants = cva(
"inline-flex items-center rounded-md border border-zinc-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:ring-offset-2 dark:border-zinc-800 dark:focus:ring-zinc-300",
{
variants: {
variant: {
default:
"border-transparent bg-zinc-900 text-zinc-50 shadow hover:bg-zinc-900/80 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-50/80",
secondary:
"border-transparent bg-zinc-100 text-zinc-900 hover:bg-zinc-100/80 dark:bg-zinc-800 dark:text-zinc-50 dark:hover:bg-zinc-800/80",
destructive:
"border-transparent bg-red-500 text-zinc-50 shadow hover:bg-red-500/80 dark:bg-red-900 dark:text-zinc-50 dark:hover:bg-red-900/80",
outline: "text-zinc-950 dark:text-zinc-50",
},
},
defaultVariants: {
variant: "default",
},
}
)

export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
)
}

export { Badge, badgeVariants }
41 changes: 21 additions & 20 deletions docs/docs.trychroma.com/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "../../lib/utils"
import { cn } from "@/lib/utils";

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
"bg-zinc-900 text-zinc-50 shadow hover:bg-zinc-900/90 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-50/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
"bg-red-500 text-zinc-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-zinc-50 dark:hover:bg-red-900/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
"border border-zinc-200 bg-white shadow-sm hover:bg-zinc-100 hover:text-zinc-900 dark:border-zinc-800 dark:bg-zinc-950 dark:hover:bg-zinc-800 dark:hover:text-zinc-50",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
"bg-zinc-100 text-zinc-900 shadow-sm hover:bg-zinc-100/80 dark:bg-zinc-800 dark:text-zinc-50 dark:hover:bg-zinc-800/80",
ghost:
"hover:bg-zinc-100 hover:text-zinc-900 dark:hover:bg-zinc-800 dark:hover:text-zinc-50",
link: "text-zinc-900 underline-offset-4 hover:underline dark:text-zinc-50",
},
size: {
default: "h-9 px-4 py-2",
@@ -31,27 +32,27 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
}
)
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants }
export { Button, buttonVariants };
118 changes: 118 additions & 0 deletions docs/docs.trychroma.com/components/ui/drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use client"

import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"

import { cn } from "@/lib/utils"

const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"

const DrawerTrigger = DrawerPrimitive.Trigger

const DrawerPortal = DrawerPrimitive.Portal

const DrawerClose = DrawerPrimitive.Close

const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName

const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-zinc-100 dark:bg-zinc-800" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"

const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"

const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"

const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName

const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-zinc-500 dark:text-zinc-400", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName

export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
18 changes: 10 additions & 8 deletions docs/docs.trychroma.com/components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client"

import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import {
@@ -6,7 +8,7 @@ import {
DotFilledIcon,
} from "@radix-ui/react-icons"

import { cn } from "../../lib/utils"
import { cn } from "@/lib/utils"

const DropdownMenu = DropdownMenuPrimitive.Root

@@ -29,7 +31,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-zinc-100 data-[state=open]:bg-zinc-100 dark:focus:bg-zinc-800 dark:data-[state=open]:bg-zinc-800",
inset && "pl-8",
className
)}
@@ -49,7 +51,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-200 bg-white p-1 text-zinc-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-50",
className
)}
{...props}
@@ -67,7 +69,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-200 bg-white p-1 text-zinc-950 shadow-md dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-50",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
@@ -86,7 +88,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-800 dark:focus:text-zinc-50",
inset && "pl-8",
className
)}
@@ -102,7 +104,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-800 dark:focus:text-zinc-50",
className
)}
checked={checked}
@@ -126,7 +128,7 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-800 dark:focus:text-zinc-50",
className
)}
{...props}
@@ -165,7 +167,7 @@ const DropdownMenuSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
className={cn("-mx-1 my-1 h-px bg-zinc-100 dark:bg-zinc-800", className)}
{...props}
/>
))
120 changes: 120 additions & 0 deletions docs/docs.trychroma.com/components/ui/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from "react";

import { cn } from "@/lib/utils";

const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
));
Table.displayName = "Table";

const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
));
TableHeader.displayName = "TableHeader";

const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
));
TableBody.displayName = "TableBody";

const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t bg-zinc-100/50 font-medium [&>tr]:last:border-b-0 dark:bg-zinc-800/50",
className,
)}
{...props}
/>
));
TableFooter.displayName = "TableFooter";

const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors data-[state=selected]:bg-zinc-100 dark:data-[state=selected]:bg-zinc-800",
className,
)}
{...props}
/>
));
TableRow.displayName = "TableRow";

const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-10 px-2 text-left align-middle font-medium text-zinc-500 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] dark:text-zinc-400",
className,
)}
{...props}
/>
));
TableHead.displayName = "TableHead";

const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn(
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
{...props}
/>
));
TableCell.displayName = "TableCell";

const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-zinc-500 dark:text-zinc-400", className)}
{...props}
/>
));
TableCaption.displayName = "TableCaption";

export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
};
34 changes: 17 additions & 17 deletions docs/docs.trychroma.com/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";

import { cn } from "../../lib/utils"
import { cn } from "@/lib/utils";

const Tabs = TabsPrimitive.Root
const Tabs = TabsPrimitive.Root;

const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
@@ -12,13 +12,13 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
className
"inline-flex h-9 items-center justify-center rounded-lg bg-zinc-100 p-1 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400",
className,
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
));
TabsList.displayName = TabsPrimitive.List.displayName;

const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
@@ -27,13 +27,13 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
className
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-white transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-zinc-950 data-[state=active]:shadow dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300 dark:data-[state=active]:bg-zinc-950 dark:data-[state=active]:text-zinc-50",
className,
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;

const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
@@ -42,12 +42,12 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
"mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300",
className,
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
));
TabsContent.displayName = TabsPrimitive.Content.displayName;

export { Tabs, TabsList, TabsTrigger, TabsContent }
export { Tabs, TabsList, TabsTrigger, TabsContent };
11 changes: 11 additions & 0 deletions docs/docs.trychroma.com/components/ui/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client";

import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes/dist/types";

const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
};

export default ThemeProvider;
127 changes: 0 additions & 127 deletions docs/docs.trychroma.com/components/ui/toast.tsx

This file was deleted.

33 changes: 0 additions & 33 deletions docs/docs.trychroma.com/components/ui/toaster.tsx

This file was deleted.

24 changes: 14 additions & 10 deletions docs/docs.trychroma.com/components/ui/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"use client"

import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"

import { cn } from "../../lib/utils"
import { cn } from "@/lib/utils"

const TooltipProvider = TooltipPrimitive.Provider

@@ -13,15 +15,17 @@ const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:bg-zinc-50 dark:text-zinc-900",
className
)}
{...props}
/>
</TooltipPrimitive.Portal>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

37 changes: 37 additions & 0 deletions docs/docs.trychroma.com/components/ui/ui-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import { Button, buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { VariantProps } from "class-variance-authority";

interface UIButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
children?: React.ReactNode;
asChild?: boolean;
}

const UIButton = React.forwardRef<HTMLButtonElement, UIButtonProps>(
({ children, className, variant, size, ...props }, ref) => {
const customStyles = cn(
"flex items-center justify-center border-x-[0.9px] border-y-[1px] shadow outline-none h-full rounded py-[0.2rem]",
"text-[#27201C] bg-gradient-to-b from-[#FFFFFF] to-[#f9f9f9] border-[#171716]/40 hover:bg-gradient-to-b hover:from-gray-100 hover:to-gray-100",
"dark:text-[#fff] dark:bg-gradient-to-b dark:from-[#171716] dark:to-[#171716] border-[0.8px] dark:border-[#fff]/40 dark:hover:from-[#171716]/90 dark:hover:to-[#171716]/90",
className,
);

return (
<Button
ref={ref}
variant={variant}
size={size}
className={customStyles}
{...props}
>
{children}
</Button>
);
},
);
UIButton.displayName = "UIButton";

export default UIButton;
192 changes: 0 additions & 192 deletions docs/docs.trychroma.com/components/ui/use-toast.ts

This file was deleted.

45 changes: 45 additions & 0 deletions docs/docs.trychroma.com/context/app-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, {
createContext,
useState,
ReactNode,
useContext,
useEffect,
} from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";

export interface AppContextValue {
language: string;
setLanguage: (language: string) => void;
}

const AppContextDefaultValue: AppContextValue = {
language: "python",
setLanguage: () => {},
};

const AppContext = createContext<AppContextValue>(AppContextDefaultValue);

export const AppContextProvider = ({ children }: { children: ReactNode }) => {
const searchParams = useSearchParams();
const [language, setLanguage] = useState<string>(
searchParams.get("lang") || "python",
);
const router = useRouter();
const pathname = usePathname();

useEffect(() => {
if (language === "typescript") {
router.replace(`${pathname}?lang=typescript`);
} else {
router.replace(pathname);
}
}, [language]);

return (
<AppContext.Provider value={{ language, setLanguage }}>
{children}
</AppContext.Provider>
);
};

export default AppContext;
73 changes: 73 additions & 0 deletions docs/docs.trychroma.com/lib/content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { LucideIcon } from "lucide-react";

export interface AppPage {
id: string;
name: string;
slug?: string;
path?: string;
}

export interface AppSection {
id: string;
name: string;
default?: string;
icon?: LucideIcon;
pages?: AppPage[];
generatePages?: boolean;
subsections?: AppSection[];
comingSoon?: boolean;
}

export const getAllPages = (sidebarConfig: AppSection[], sectionId: string) => {
const section = sidebarConfig.find((section) => section.id === sectionId);
if (!section) {
return [];
}

const pages: { id: string; name: string; slug: string }[] = [];

pages.push(
...(section.pages?.map((page) => {
return {
...page,
slug: `${section.id}/${page.id}`,
path: `./${page.slug}`,
};
}) || []),
);

section.subsections?.forEach((subsection) => {
pages.push(
...(subsection.pages?.map((page) => {
return {
...page,
slug: `${section.id}/${subsection.id}/${page.id}`,
path: `../${subsection.id}/${page.id}`,
};
}) || []),
);
});

return pages;
};

export const getPagePrevNext = (
slug: string[],
pages: AppPage[],
): {
prev?: AppPage;
next?: AppPage;
} => {
const page = slug.join("/");
const pageIndex = pages.map((page) => page.slug).indexOf(page);
if (pageIndex === -1) {
return { prev: undefined, next: undefined };
}
if (pageIndex === pages.length - 1) {
return { prev: pages[pageIndex - 1], next: undefined };
}
if (pageIndex === 0) {
return { prev: undefined, next: pages[pageIndex + 1] };
}
return { prev: pages[pageIndex - 1], next: pages[pageIndex + 1] };
};
18 changes: 13 additions & 5 deletions docs/docs.trychroma.com/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export const cn = (...inputs: ClassValue[]) => {
return twMerge(clsx(inputs));
};

export const formatToK = (num: number) => {
return `${Math.round(num / 1000)}k`;
};

export const capitalize = (str: string) => {
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
};
134 changes: 134 additions & 0 deletions docs/docs.trychroma.com/markdoc/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import type { Config } from "@markdoc/markdoc";
import React from "react";
import InlineCode from "@/components/markdoc/inline-code";
import CodeBlock from "@/components/markdoc/code-block";
import TabbedUseCaseCodeBlock from "@/components/markdoc/tabbed-use-case-code-block";
import Tab, { MarkdocTabs } from "@/components/markdoc/markdoc-tabs";
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@/components/markdoc/table";
import TabbedCodeBlock from "@/components/markdoc/tabbed-code-block";
import CenteredContent from "@/components/markdoc/centered-content";
import Latex from "@/components/markdoc/latex";
import Banner from "@/components/markdoc/banner";
import Heading from "@/components/markdoc/markdoc-heading";

interface MarkDocConfig extends Config {
components?: Record<string, React.FC<any>>;
}

const markdocConfig: MarkDocConfig = {
nodes: {
code: {
render: "InlineCode",
attributes: {
content: { type: String },
},
},
fence: {
render: "CodeBlock",
attributes: {
content: { type: String },
language: { type: String },
},
},
table: {
render: "Table",
},
thead: {
render: "TableHeader",
},
tbody: {
render: "TableBody",
},
tr: {
render: "TableRow",
},
th: {
render: "TableHead",
},
td: {
render: "TableCell",
},
heading: {
render: "Heading",
attributes: {
level: { type: "Number", required: true },
id: { type: "String", required: false },
},
},
},
tags: {
TabbedCodeBlock: {
render: "TabbedCodeBlock",
selfClosing: true,
},
TabbedUseCaseCodeBlock: {
render: "TabbedUseCaseCodeBlock",
selfClosing: false,
attributes: {
language: {
type: String,
required: true,
},
},
},
Tab: {
render: "Tab",
selfClosing: false,
attributes: {
label: {
type: String,
required: true,
},
},
},
Tabs: {
render: "Tabs",
selfClosing: false,
},
CenteredContent: {
render: "CenteredContent",
selfClosing: false,
},
Banner: {
render: "Banner",
attributes: {
type: {
type: String,
required: true,
},
},
selfClosing: false,
},
Latex: {
render: "Latex",
selfClosing: false,
},
},
components: {
InlineCode,
CodeBlock,
TabbedCodeBlock,
TabbedUseCaseCodeBlock,
Tab,
Tabs: MarkdocTabs,
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
CenteredContent,
Banner,
Latex,
Heading,
},
};

export default markdocConfig;
38 changes: 38 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/cli/install-and-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Install and Run

You can install the Chroma CLI with `pip`:

```terminal
pip install chromadb
```

You can then run a Chroma server locally with the `chroma run` command:

```terminal
chroma run --path [/path/to/persist/data]
```

Your Chroma server will persist its data in the path you provide after the `path` argument. By default,
it will save data to the `.chroma` directory.

With your Chroma server running, you can connect to it with the `HttpClient`:

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
import chromadb

chroma_client = chromadb.HttpClient(host='localhost', port=8000)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
import { ChromaClient } from "chromadb";

const client = new ChromaClient();
```
{% /Tab %}

{% /TabbedCodeBlock %}
17 changes: 17 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/cli/vacuum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Vacuuming

Vacuuming shrinks and optimizes your database.

Vacuuming after upgrading from a version of Chroma below v0.5.6 will greatly reduce the size of your database and enable continuous database pruning. A warning is logged during server startup if this is necessary.

In most other cases, vacuuming is unnecessary. **It does not need to be run regularly**.

Vacuuming blocks all reads and writes to your database while it's running, so we recommend shutting down your Chroma server before vacuuming (although it's not strictly required).

To vacuum your database, run:

```bash
chroma utils vacuum --path <your-data-directory>
```

For large databases, expect this to take up to a few minutes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Adding Data to Chroma Collections

Add data to Chroma with `.add`.

Raw documents:

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.add(
documents=["lorem ipsum...", "doc2", "doc3", ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
ids=["id1", "id2", "id3", ...]
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.add({
ids: ["id1", "id2", "id3", ...],
metadatas: [{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents: ["lorem ipsum...", "doc2", "doc3", ...],
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

If Chroma is passed a list of `documents`, it will automatically tokenize and embed them with the collection's embedding function (the default will be used if none was supplied at collection creation). Chroma will also store the `documents` themselves. If the documents are too large to embed using the chosen embedding function, an exception will be raised.

Each document must have a unique associated `id`. Trying to `.add` the same ID twice will result in only the initial value being stored. An optional list of `metadata` dictionaries can be supplied for each document, to store additional information and enable filtering.

Alternatively, you can supply a list of document-associated `embeddings` directly, and Chroma will store the associated documents without embedding them itself.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.add(
documents=["doc1", "doc2", "doc3", ...],
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
ids=["id1", "id2", "id3", ...]
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.add({
ids: ["id1", "id2", "id3", ...],
embeddings: [[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas: [{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents: ["lorem ipsum...", "doc2", "doc3", ...],
})
```
{% /Tab %}

{% /TabbedCodeBlock %}

If the supplied `embeddings` are not the same dimension as the collection, an exception will be raised.

You can also store documents elsewhere, and just supply a list of `embeddings` and `metadata` to Chroma. You can use the `ids` to associate the embeddings with your documents stored elsewhere.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.add(
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
ids=["id1", "id2", "id3", ...]
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.add({
ids: ["id1", "id2", "id3", ...],
embeddings: [[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas: [{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
})
```
{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Configuring Chroma Collections

You can configure the embedding space of a collection by setting special keys on a collection's metadata. These configurations will help you customize your Chroma collections for different data, accuracy and performance requirements.

* `hnsw:space` defines the distance function of the embedding space. The default is `l2` (squared L2 norm), and other possible values are `cosine` (cosine similarity), and `ip` (inner product).

| Distance | parameter | Equation |
| ----------------- | :-------: |-----------------------------------------------------------------------------------------------------------------------------------------------------------:|
| Squared L2 | `l2` | {% Latex %} d = \\sum\\left(A_i-B_i\\right)^2 {% /Latex %} |
| Inner product | `ip` | {% Latex %} d = 1.0 - \\sum\\left(A_i \\times B_i\\right) {% /Latex %} |
| Cosine similarity | `cosine` | {% Latex %} d = 1.0 - \\frac{\\sum\\left(A_i \\times B_i\\right)}{\\sqrt{\\sum\\left(A_i^2\\right)} \\cdot \\sqrt{\\sum\\left(B_i^2\\right)}} {% /Latex %} |

* `hnsw:ef_construction` determines the size of the candidate list used to select neighbors during index creation. A higher value improves index quality at the cost of more memory and time, while a lower value speeds up construction with reduced accuracy. The default value is `100`.
* `hnsw:ef_search` determines the size of the dynamic candidate list used while searching for the nearest neighbors. A higher value improves recall and accuracy by exploring more potential neighbors but increases query time and computational cost, while a lower value results in faster but less accurate searches. The default value is `10`.
* `hnsw:M` is the maximum number of neighbors (connections) that each node in the graph can have during the construction of the index. A higher value results in a denser graph, leading to better recall and accuracy during searches but increases memory usage and construction time. A lower value creates a sparser graph, reducing memory usage and construction time but at the cost of lower search accuracy and recall. The default value is `16`.
* `hnsw:num_threads` specifies the number of threads to use during index construction or search operations. The default value is `multiprocessing.cpu_count()` (available CPU cores).

Here is an example of how you can create a collection and configure it with custom HNSW settings:

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection = client.create_collection(
name="my_collection",
embedding_function=emb_fn,
metadata={
"hnsw:space": "cosine",
"hnsw:ef_search": 100
}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
let collection = await client.createCollection({
name: "my_collection",
embeddingFunction: emb_fn,
metadata: {
"hnsw:space": "cosine",
"hnsw:ef_search": 100
}
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

You can learn more in our [Embeddings section](../embeddings/embedding-functions).
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Create, Get, and Delete Chroma Collections

Chroma lets you manage collections of embeddings, using the `collection` primitive.

Chroma uses collection names in the url, so there are a few restrictions on naming them:

- The length of the name must be between 3 and 63 characters.
- The name must start and end with a lowercase letter or a digit, and it can contain dots, dashes, and underscores in between.
- The name must not contain two consecutive dots.
- The name must not be a valid IP address.

Chroma collections are created with a name and an optional embedding function.

{% Banner type="note" %}
If you supply an embedding function, you must supply it every time you get the collection.
{% /Banner %}

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection = client.create_collection(name="my_collection", embedding_function=emb_fn)
collection = client.get_collection(name="my_collection", embedding_function=emb_fn)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
let collection = await client.createCollection({
name: "my_collection",
embeddingFunction: emb_fn,
});

collection = await client.getCollection({
name: "my_collection",
embeddingFunction: emb_fn,
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

The embedding function takes text as input and embeds it. If no embedding function is supplied, Chroma will use [sentence transformer](https://www.sbert.net/index.html) as a default. You can learn more about [embedding functions](../embeddings/embedding-functions), and how to create your own.

When creating collections, you can pass the optional `metadata` argument to add a mapping of metadata key-value pairs to your collections. This can be useful for adding general about the collection like creation time, description of the data stored in the collection, and more.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
from datetime import datetime

collection = client.create_collection(
name="my_collection",
embedding_function=emb_fn,
metadata={
"description": "my first Chroma collection",
"created": str(datetime.now())
}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
let collection = await client.createCollection({
name: "my_collection",
embeddingFunction: emb_fn,
metadata: {
description: "my first Chroma collection",
created: (new Date()).toString()
}
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

The collection metadata is also used to configure the embedding space of a collection. Learn more about it in [Configuring Chroma Collections](./configure).

The Chroma client allows you to get and delete existing collections by their name. It also offers a `get or create` method to get a collection if it exists, or create it otherwise.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection = client.get_collection(name="test") # Get a collection object from an existing collection, by name. Will raise an exception if it's not found.
collection = client.get_or_create_collection(name="test") # Get a collection object from an existing collection, by name. If it doesn't exist, create it.
client.delete_collection(name="my_collection") # Delete a collection and all associated embeddings, documents, and metadata. ⚠️ This is destructive and not reversible
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
const collection = await client.getCollection({ name: "test" }); // Get a collection object from an existing collection, by name. Will raise an exception of it's not found.
collection = await client.getOrCreateCollection({ name: "test" }); // Get a collection object from an existing collection, by name. If it doesn't exist, create it.
await client.deleteCollection(collection); // Delete a collection and all associated embeddings, documents, and metadata. ⚠️ This is destructive and not reversible
```
{% /Tab %}

{% /TabbedCodeBlock %}

Collections have a few useful convenience methods.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.peek() # returns a list of the first 10 items in the collection
collection.count() # returns the number of items in the collection
collection.modify(name="new_name") # Rename the collection
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.peek(); // returns a list of the first 10 items in the collection
await collection.count(); // returns the number of items in the collection
await collection.modify({ name: "new_name" }) // Rename the collection
```
{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Deleting Data from Chroma Collections

Chroma supports deleting items from a collection by `id` using `.delete`. The embeddings, documents, and metadata associated with each item will be deleted.

{% Banner type="warn" %}
Naturally, this is a destructive operation, and cannot be undone.
{% /Banner %}

`.delete` also supports the `where` filter. If no `ids` are supplied, it will delete all items in the collection that match the `where` filter.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.delete(
ids=["id1", "id2", "id3",...],
where={"chapter": "20"}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.delete({
ids: ["id1", "id2", "id3",...], //ids
where: {"chapter": "20"} //where
})
```
{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Updating Data in Chroma Collections

Any property of records in a collection can be updated with `.update`:

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.update(
ids=["id1", "id2", "id3", ...],
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents=["doc1", "doc2", "doc3", ...],
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.update({
ids: ["id1", "id2", "id3", ...],
embeddings: [[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas: [{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents: ["doc1", "doc2", "doc3", ...]
})
```
{% /Tab %}

{% /TabbedCodeBlock %}

If an `id` is not found in the collection, an error will be logged and the update will be ignored. If `documents` are supplied without corresponding `embeddings`, the embeddings will be recomputed with the collection's embedding function.

If the supplied `embeddings` are not the same dimension as the collection, an exception will be raised.

Chroma also supports an `upsert` operation, which updates existing items, or adds them if they don't yet exist.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.upsert(
ids=["id1", "id2", "id3", ...],
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents=["doc1", "doc2", "doc3", ...],
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.upsert({
ids: ["id1", "id2", "id3"],
embeddings: [
[1.1, 2.3, 3.2],
[4.5, 6.9, 4.4],
[1.1, 2.3, 3.2],
],
metadatas: [
{ chapter: "3", verse: "16" },
{ chapter: "3", verse: "5" },
{ chapter: "29", verse: "11" },
],
documents: ["doc1", "doc2", "doc3"],
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

If an `id` is not present in the collection, the corresponding items will be created as per `add`. Items with existing `id`s will be updated as per `update`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Embedding Functions

Embeddings are the way to represent any kind of data, making them the perfect fit for working with all kinds of A.I-powered tools and algorithms. They can represent text, images, and soon audio and video. There are many options for creating embeddings, whether locally using an installed library, or by calling an API.

Chroma provides lightweight wrappers around popular embedding providers, making it easy to use them in your apps. You can set an embedding function when you create a Chroma collection, which will be used automatically, or you can call them directly yourself.

| | Python | Typescript |
|------------------------------------------------------------------------------------------|--------|------------|
| [OpenAI](../../integrations/embedding-models/openai) |||
| [Google Generative AI](../../integrations/embedding-models/google-gemini) |||
| [Cohere](../../integrations/embedding-models/cohere) |||
| [Hugging Face](../../integrations/embedding-models/hugging-face) || - |
| [Instructor](../../integrations/embedding-models/instructor) || - |
| [Hugging Face Embedding Server](../../integrations/embedding-models/hugging-face-server) |||
| [Jina AI](../../integrations/embedding-models/jinaai) |||

We welcome pull requests to add new Embedding Functions to the community.

***

## Default: all-MiniLM-L6-v2

By default, Chroma uses the [Sentence Transformers](https://www.sbert.net/) `all-MiniLM-L6-v2` model to create embeddings. This embedding model can create sentence and document embeddings that can be used for a wide variety of tasks. This embedding function runs locally on your machine, and may require you download the model files (this will happen automatically).

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
from chromadb.utils import embedding_functions
default_ef = embedding_functions.DefaultEmbeddingFunction()
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
import { DefaultEmbeddingFunction } from "chromadb";
const defaultEF = new DefaultEmbeddingFunction();
```
{% /Tab %}

{% /TabbedCodeBlock %}

Embedding functions can be linked to a collection and used whenever you call `add`, `update`, `upsert` or `query`. You can also use them directly which can be handy for debugging.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
val = default_ef(["foo"])
print(val) # [[0.05035809800028801, 0.0626462921500206, -0.061827320605516434...]]
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
const val = defaultEf.generate(["foo"]);
console.log(val); // [[0.05035809800028801, 0.0626462921500206, -0.061827320605516434...]]
```
{% /Tab %}

{% /TabbedCodeBlock %}

## Sentence Transformers

Chroma can also use any [Sentence Transformers](https://www.sbert.net/) model to create embeddings.

You can pass in an optional `model_name` argument, which lets you choose which Sentence Transformers model to use. By default, Chroma uses `all-MiniLM-L6-v2`. You can see a list of all available models [here](https://www.sbert.net/docs/pretrained_models.html).

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="all-MiniLM-L6-v2"
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
import { DefaultEmbeddingFunction } from "chromadb";
const modelName = "all-MiniLM-L6-v2";
const defaultEF = new DefaultEmbeddingFunction(modelName);
```
{% /Tab %}

{% /TabbedCodeBlock %}

## Custom Embedding Functions

You can create your own embedding function to use with Chroma, it just needs to implement the `EmbeddingFunction` protocol.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
from chromadb import Documents, EmbeddingFunction, Embeddings

class MyEmbeddingFunction(EmbeddingFunction):
def __call__(self, input: Documents) -> Embeddings:
# embed the documents somehow
return embeddings
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
class MyEmbeddingFunction {
private api_key: string;

constructor(api_key: string) {
this.api_key = api_key;
}

public async generate(texts: string[]): Promise<number[][]> {
// do things to turn texts into embeddings with an api_key perhaps
return embeddings;
}
}
```
{% /Tab %}

{% /TabbedCodeBlock %}

We welcome contributions! If you create an embedding function that you think would be useful to others, please consider [submitting a pull request](https://github.com/chroma-core/chroma) to add it to Chroma's `embedding_functions` module.
129 changes: 129 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/docs/embeddings/multimodal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Multimodal

{% Banner type="note" %}
Multimodal support is currently available only in Python. Javascript/Typescript support coming soon!
{% /Banner %}

Chroma supports multimodal collections, i.e. collections which can store, and can be queried by, multiple modalities of data.

[Try it out in Colab](https://githubtocolab.com/chroma-core/chroma/blob/main/examples/multimodal/multimodal_retrieval.ipynb)

## Multi-modal Embedding Functions

Chroma supports multi-modal embedding functions, which can be used to embed data from multiple modalities into a single embedding space.

Chroma has the OpenCLIP embedding function built in, which supports both text and images.

```python
from chromadb.utils.embedding_functions import OpenCLIPEmbeddingFunction
embedding_function = OpenCLIPEmbeddingFunction()
```

## Data Loaders

Chroma supports data loaders, for storing and querying with data stored outside Chroma itself, via URI. Chroma will not store this data, but will instead store the URI, and load the data from the URI when needed.

Chroma has a data loader for loading images from a filesystem built in.

```python
from chromadb.utils.data_loaders import ImageLoader
data_loader = ImageLoader()
```

## Multi-modal Collections

You can create a multi-modal collection by passing in a multi-modal embedding function. In order to load data from a URI, you must also pass in a data loader.

```python
import chromadb

client = chromadb.Client()

collection = client.create_collection(
name='multimodal_collection',
embedding_function=embedding_function,
data_loader=data_loader)

```

### Adding data

You can add data to a multi-modal collection by specifying the data modality. For now, images are supported:

```python
collection.add(
ids=['id1', 'id2', 'id3'],
images=[...] # A list of numpy arrays representing images
)
```

Note that Chroma will not store the data for you, and you will have to maintain a mapping from IDs to data yourself.

However, you can use Chroma in combination with data stored elsewhere, by adding it via URI. Note that this requires that you have specified a data loader when creating the collection.

```python
collection.add(
ids=['id1', 'id2', 'id3'],
uris=[...] # A list of strings representing URIs to data
)
```

Since the embedding function is multi-modal, you can also add text to the same collection:

```python
collection.add(
ids=['id4', 'id5', 'id6'],
documents=["This is a document", "This is another document", "This is a third document"]
)
```

### Querying

You can query a multi-modal collection with any of the modalities that it supports. For example, you can query with images:

```python
results = collection.query(
query_images=[...] # A list of numpy arrays representing images
)
```

Or with text:

```python
results = collection.query(
query_texts=["This is a query document", "This is another query document"]
)
```

If a data loader is set for the collection, you can also query with URIs which reference data stored elsewhere of the supported modalities:

```python
results = collection.query(
query_uris=[...] # A list of strings representing URIs to data
)
```

Additionally, if a data loader is set for the collection, and URIs are available, you can include the data in the results:

```python
results = collection.query(
query_images=[...], # # list of numpy arrays representing images
includes=['data']
)
```

This will automatically call the data loader for any available URIs, and include the data in the results. `uris` are also available as an `includes` field.

### Updating

You can update a multi-modal collection by specifying the data modality, in the same way as `add`. For now, images are supported:

```python
collection.update(
ids=['id1', 'id2', 'id3'],
images=[...] # A list of numpy arrays representing images
)
```

Note that a given entry with a specific ID can only have one associated modality at a time. Updates will over-write the existing modality, so for example, an entry which originally has corresponding text and updated with an image, will no longer have that text after an update with images.

Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
{
"id": "embeddings-guide",
"title": "Embeddings",
"section": "Guides",
"order": 1
}
---

# Embeddings

Embeddings are the A.I-native way to represent any kind of data, making them the perfect fit for working with all kinds of A.I-powered tools and algorithms. They can represent text, images, and soon audio and video. There are many options for creating embeddings, whether locally using an installed library, or by calling an API.

Chroma provides lightweight wrappers around popular embedding providers, making it easy to use them in your apps. You can set an embedding function when you create a Chroma collection, which will be used automatically, or you can call them directly yourself.

{% special_table %}
{% /special_table %}

| | Python | JS |
|--------------|-----------|---------------|
| [OpenAI](/integrations/openai) |||
| [Google Generative AI](/integrations/google-gemini) |||
| [Cohere](/integrations/cohere) |||
| [Hugging Face](/integrations/hugging-face) |||
| [Instructor](/integrations/instructor) |||
| [Hugging Face Embedding Server](/integrations/hugging-face-server) |||
| [Jina AI](/integrations/jinaai) |||

We welcome pull requests to add new Embedding Functions to the community.

***

## Default: all-MiniLM-L6-v2

By default, Chroma uses the [Sentence Transformers](https://www.sbert.net/) `all-MiniLM-L6-v2` model to create embeddings. This embedding model can create sentence and document embeddings that can be used for a wide variety of tasks. This embedding function runs locally on your machine, and may require you download the model files (this will happen automatically).

```python
from chromadb.utils import embedding_functions
default_ef = embedding_functions.DefaultEmbeddingFunction()
```

{% note type="default" %}
Embedding functions can be linked to a collection and used whenever you call `add`, `update`, `upsert` or `query`. You can also use them directly which can be handy for debugging.
```py
val = default_ef(["foo"])
```
-> [[0.05035809800028801, 0.0626462921500206, -0.061827320605516434...]]
{% /note %}


{% tabs group="code-lang" hideTabs=true %}
{% tab label="Python" %}

## Sentence Transformers

Chroma can also use any [Sentence Transformers](https://www.sbert.net/) model to create embeddings.

```python
sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="all-MiniLM-L6-v2")
```

You can pass in an optional `model_name` argument, which lets you choose which Sentence Transformers model to use. By default, Chroma uses `all-MiniLM-L6-v2`. You can see a list of all available models [here](https://www.sbert.net/docs/pretrained_models.html).

{% /tab %}
{% tab label="Javascript" %}
{% /tab %}
{% /tabs %}


***


## Custom Embedding Functions

{% tabs group="code-lang" hideContent=true %}

{% tab label="Python" %}
{% /tab %}

{% tab label="Javascript" %}
{% /tab %}

{% /tabs %}

{% tabs group="code-lang" hideTabs=true %}
{% tab label="Python" %}

You can create your own embedding function to use with Chroma, it just needs to implement the `EmbeddingFunction` protocol.

```python
from chromadb import Documents, EmbeddingFunction, Embeddings

class MyEmbeddingFunction(EmbeddingFunction):
def __call__(self, input: Documents) -> Embeddings:
# embed the documents somehow
return embeddings
```

We welcome contributions! If you create an embedding function that you think would be useful to others, please consider [submitting a pull request](https://github.com/chroma-core/chroma) to add it to Chroma's `embedding_functions` module.


{% /tab %}
{% tab label="Javascript" %}

You can create your own embedding function to use with Chroma, it just needs to implement the `EmbeddingFunction` protocol. The `.generate` method in a class is strictly all you need.

```javascript
class MyEmbeddingFunction {
private api_key: string;

constructor(api_key: string) {
this.api_key = api_key;
}

public async generate(texts: string[]): Promise<number[][]> {
// do things to turn texts into embeddings with an api_key perhaps
return embeddings;
}
}
```

{% /tab %}
{% /tabs %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
{
"id": "multimodal-guide",
"title": "Multimodal",
"section": "Guides",
"order": 2
}
---

# Multimodal

{% tabs group="code-lang" hideContent=true %}

{% tab label="Python" %}
{% /tab %}

{% tab label="Javascript" %}
{% /tab %}

{% /tabs %}

---

{% tabs group="code-lang" hideTabs=true %}
{% tab label="Python" %}

Chroma supports multimodal collections, i.e. collections which can store, and can be queried by, multiple modalities of data.

Try it out in Colab: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://githubtocolab.com/chroma-core/chroma/blob/main/examples/multimodal/multimodal_retrieval.ipynb)

## Multi-modal Embedding Functions

Chroma supports multi-modal embedding functions, which can be used to embed data from multiple modalities into a single embedding space.

Chroma has the OpenCLIP embedding function built in, which supports both text and images.

```python
from chromadb.utils.embedding_functions import OpenCLIPEmbeddingFunction
embedding_function = OpenCLIPEmbeddingFunction()
```

## Data Loaders

Chroma supports data loaders, for storing and querying with data stored outside Chroma itself, via URI. Chroma will not store this data, but will instead store the URI, and load the data from the URI when needed.

Chroma has an data loader for loading images from a filesystem built in.

```python
from chromadb.utils.data_loaders import ImageLoader
data_loader = ImageLoader()
```

## Multi-modal Collections

You can create a multi-modal collection by passing in a multi-modal embedding function. In order to load data from a URI, you must also pass in a data loader.

```python
import chromadb

client = chromadb.Client()

collection = client.create_collection(
name='multimodal_collection',
embedding_function=embedding_function,
data_loader=data_loader)

```

### Adding data

You can add data to a multi-modal collection by specifying the data modality. For now, images are supported:

```python
collection.add(
ids=['id1', 'id2', 'id3'],
images=[...] # A list of numpy arrays representing images
)
```

Note that Chroma will not store the data for you, and you will have to maintain a mapping from IDs to data yourself.

However, you can use Chroma in combination with data stored elsewhere, by adding it via URI. Note that this requires that you have specified a data loader when creating the collection.

```python
collection.add(
ids=['id1', 'id2', 'id3'],
uris=[...] # A list of strings representing URIs to data
)
```

Since the embedding function is multi-modal, you can also add text to the same collection:

```python
collection.add(
ids=['id4', 'id5', 'id6'],
documents=["This is a document", "This is another document", "This is a third document"]
)
```

### Querying

You can query a multi-modal collection with any of the modalities that it supports. For example, you can query with images:

```python
results = collection.query(
query_images=[...] # A list of numpy arrays representing images
)
```

Or with text:

```python
results = collection.query(
query_texts=["This is a query document", "This is another query document"]
)
```

If a data loader is set for the collection, you can also query with URIs which reference data stored elsewhere of the supported modalities:

```python
results = collection.query(
query_uris=[...] # A list of strings representing URIs to data
)
```

Additionally, if a data loader is set for the collection, and URIs are available, you can include the data in the results:

```python
results = collection.query(
query_images=[...], # # list of numpy arrays representing images
includes=['data']
)
```

This will automatically call the data loader for any available URIs, and include the data in the results. `uris` are also available as an `includes` field.

### Updating

You can update a multi-modal collection by specifying the data modality, in the same way as `add`. For now, images are supported:

```python
collection.update(
ids=['id1', 'id2', 'id3'],
images=[...] # A list of numpy arrays representing images
)
```

Note that a given entry with a specific ID can only have one associated modality at a time. Updates will over-write the existing modality, so for example, an entry which originally has corresponding text and updated with an image, will no longer have that text after an update with images.

{% /tab %}
{% tab label="Javascript" %}

Support for multi-modal retrieval for Chroma's JavaScript client is coming soon!

{% /tab %}

{% /tabs %}

851 changes: 851 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/docs/guides/usage-guide.md

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/docs/overview/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
{
"id": "about",
"title": "About",
"section": "Overview",
"order": 4
}
---

# About

{% Banner type="tip" title="We are hiring" %}
We are hiring software engineers and applied research scientists.
{% /Banner %}

## Who we are

[View open roles](https://careers.trychroma.com/)

Chroma as a project is coordinated by a small team of full-time employees who work at a company also called Chroma.

We work in the sunny Mission District in San Francisco.

Chroma is co-founded by [Jeff Huber](https://twitter.com/jeffreyhuber) (left) and [Anton Troynikov](https://twitter.com/atroyn) (right).

![](/team.JPG)

## Our commitment to open source

Chroma is a company that builds the open-source project also called Chroma.

We are committed to building open source software because we believe in the flourishing of humanity that will be unlocked through the democratization of robust, safe, and aligned AI systems. These tools need to be available to a new developer just starting in ML as well as the organizations that scale ML to millions (and billions) of users. Open source is about expanding the horizon of what’s possible.

Chroma is a _commercial_ open source company. What does that mean? We believe that organizing financially sustainable teams of people to work to manage, push and integrate the project enriches the health of the project and the community.

It is important that our values around this are very clear!

- We are committed to building Chroma as a ubiquitous open source standard
- A successful Chroma-based commercial product is essential for the success of the technology, and is a win-win for everyone. Simply put, many organizations will not adopt Chroma without the option of a commercially hosted solution; and the project must be backed by a company with a viable business model. We want to build an awesome project and an awesome business.
- We will decide what we provide exclusively in the commercial product based on clear, consistent criteria.

What code will be open source? As a general rule, any feature which an individual developer would find useful will be 100% open source forever. This approach, popularized by Gitlab, is called [buyer-based open source](https://about.gitlab.com/company/stewardship/). We believe that this is essential to accomplishing our mission.

Currently we don’t have any specific plans to monetize Chroma, we are working on a hosted service that will be launched as a free technical preview to make it easier for developers to get going. We are 100% focused on building valuable open source software with the community and for the community.


## Our investors

Chroma raised an $18M seed round led by Astasia Myers from Quiet Capital. Joining the round are angels including Naval Ravikant, Max and Jack Altman, Jordan Tigani (Motherduck), Guillermo Rauch (Vercel), Akshay Kothari (Notion), Amjad Masad (Replit), Spencer Kimball (CockroachDB), and other founders and leaders from ScienceIO, Gumroad, MongoDB, Scale, Hugging Face, Jasper and more.

{% CenteredContent %}
![chroma-investors](/investors.png)
{% /CenteredContent %}

Chroma raised a pre-seed in May 2022, led by Anthony Goldbloom (Kaggle) from AIX Ventures, James Cham from Bloomberg Beta, and Nat Friedman and Daniel Gross (AI Grant).

We're excited to work with a deep set of investors and enterpreneurs who have invested in and built some of the most successful open-source projects in the world.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
{
"id": "contributing",
"title": "Contributing",
"section": "Overview",
"order": 3
}
---

# Contributing

We welcome all contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas.

## Getting Started
Here are some helpful links to get you started with contributing to Chroma

- The Chroma codebase is hosted on [Github](https://github.com/chroma-core/chroma)
- Issues are tracked on [Github Issues](https://github.com/chroma-core/chroma/issues). Please report any issues you find there making sure to fill out the correct [form for the type of issue you are reporting](https://github.com/chroma-core/chroma/issues/new/choose).
- In order to run Chroma locally you can follow the [Development Instructions](https://github.com/chroma-core/chroma/blob/main/DEVELOP.md).
- If you want to contribute and aren't sure where to get started you can search for issues with the [Good first issue](https://github.com/chroma-core/chroma/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tag or take a look at our [Roadmap](https://docs.trychroma.com/roadmap).
- The Chroma documentation (including this page!) is hosted on [Github](https://github.com/chroma-core/docs) as well. If you find any issues with the documentation please report them on the Github Issues page for the documentation [here](https://github.com/chroma-core/docs/issues).


## Contributing Code and Ideas

### Pull Requests
In order to submit a change to Chroma please submit a [Pull Request](https://github.com/chroma-core/chroma/compare) against Chroma or the documentation. The pull request will be reviewed by the Chroma team and if approved, will be merged into the repository. We will do our best to review pull requests in a timely manner but please be patient as we are a small team. We will work to integrate your proposed changes as quickly as possible if they align with the goals of the project. We ask that you label your pull request with a title prefix that indicates the type of change you are proposing. The following prefixes are used:

```
ENH: Enhancement, new functionality
BUG: Bug fix
DOC: Additions/updates to documentation
TST: Additions/updates to tests
BLD: Updates to the build process/scripts
PERF: Performance improvement
TYP: Type annotations
CLN: Code cleanup
CHORE: Maintenance and other tasks that do not modify source or test files
```


### CIPs
Chroma Improvement Proposals or CIPs (pronounced "Chips") are the way to propose new features or large changes to Chroma. If you plan to make a large change to Chroma please submit a CIP first so that the core Chroma team as well as the community can discuss the proposed change and provide feedback. A CIP should provide a concise technical specification of the feature and a rationale for why it is needed. The CIP should be submitted as a pull request to the [CIPs folder](https://github.com/chroma-core/chroma/tree/main/docs). The CIP will be reviewed by the Chroma team and if approved will be merged into the repository. To learn more about writing a CIP you can read the [guide](https://github.com/chroma-core/chroma/blob/main/docs/CIP_Chroma_Improvment_Proposals.md). CIPs are not required for small changes such as bug fixes or documentation updates.

A CIP starts in the "Proposed" state, then moves to "Under Review" once the Chroma team has reviewed it and is considering it for implementation. Once the CIP is approved it will move to the "Accepted" state and the implementation can begin. Once the implementation is complete the CIP will move to the "Implemented" state. If the CIP is not approved it will move to the "Rejected" state. If the CIP is withdrawn by the author it will move to the "Withdrawn" state.


### Discord
For less fleshed out ideas you want to discuss with the community, you can join our [Discord](https://discord.gg/Fk2pH7k6) and chat with us in the #feature-ideas channel. We are always happy to discuss new ideas and features with the community.
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
---
{
"id": "getting-started",
"title": "Getting Started",
"section": "Overview",
"order": 1
}
---

# Getting Started

Chroma is an AI-native open-source vector database. It comes with everything you need to get started built in, and runs on your machine. A [hosted version](https://airtable.com/shrOAiDUtS2ILy5vZ) is coming soon!

### 1. Install

{% MarkdocTabs %}

{% Tab label="python" %}

```terminal
pip install chromadb
```

{% /Tab %}

{% Tab label="typescript" %}

{% TabbedUseCaseCodeBlock language="Terminal" %}

{% Tab label="yarn" %}
```terminal
yarn install chromadb chromadb-default-embed
```
{% /Tab %}

{% Tab label="npm" %}
```terminal
npm install --save chromadb chromadb-default-embed
```
{% /Tab %}

{% Tab label="pnpm" %}
```terminal
pnpm install chromadb chromadb-default-embed
```
{% /Tab %}

{% /TabbedUseCaseCodeBlock %}

Install chroma via `pip` to easily run the backend server. ([Docker](../../production/containers/docker) also available)

```terminal
pip install chromadb
```

{% /Tab %}

{% /MarkdocTabs %}

### 2. Create a Chroma Client

{% MarkdocTabs %}

{% Tab label="python" %}
```python
import chromadb
chroma_client = chromadb.Client()
```
{% /Tab %}
{% Tab label="typescript" %}

Run the Chroma backend:

{% TabbedUseCaseCodeBlock language="Terminal" %}

{% Tab label="CLI" %}
```terminal
chroma run --path ./getting-started
```
{% /Tab %}

{% Tab label="Docker" %}
```terminal
docker pull chromadb/chroma
docker run -p 8000:8000 chromadb/chroma
```
{% /Tab %}

{% /TabbedUseCaseCodeBlock %}

Then create a client which connects to it:

{% TabbedUseCaseCodeBlock language="typescript" %}

{% Tab label="ESM" %}
```typescript
import { ChromaClient } from "chromadb";
const client = new ChromaClient();
```
{% /Tab %}

{% Tab label="CJS" %}
```typescript
const { ChromaClient } = require("chromadb");
const client = new ChromaClient();
```
{% /Tab %}

{% /TabbedUseCaseCodeBlock %}

{% /Tab %}

{% /MarkdocTabs %}

### 3. Create a collection

Collections are where you'll store your embeddings, documents, and any additional metadata. Collections index your embeddings and documents, and enable efficient retrieval and filtering. You can create a collection with a name:

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection = chroma_client.create_collection(name="my_collection")
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
const collection = await client.createCollection({
name: "my_collection",
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

### 4. Add some text documents to the collection

Chroma will store your text and handle embedding and indexing automatically. You can also customize the embedding model.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.add(
documents=[
"This is a document about pineapple",
"This is a document about oranges"
],
ids=["id1", "id2"]
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.add({
documents: [
"This is a document about pineapple",
"This is a document about oranges",
],
ids: ["id1", "id2"],
});
```
{% /Tab %}

{% /TabbedCodeBlock %}

### 5. Query the collection

You can query the collection with a list of query texts, and Chroma will return the `n` most similar results. It's that easy!

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
results = collection.query(
query_texts=["This is a query document about hawaii"], # Chroma will embed this for you
n_results=2 # how many results to return
)
print(results)
```

{% /Tab %}

{% Tab label="typescript" %}
```typescript
const results = await collection.query({
queryTexts: "This is a query document about hawaii", // Chroma will embed this for you
nResults: 2, // how many results to return
});

console.log(results);
```
{% /Tab %}

{% /TabbedCodeBlock %}

If `n_results` is not provided, Chroma will return 10 results by default. Here we only added 2 documents, so we set `n_results=2`.

### 6. Inspect Results

From the above query - you can see that our query about `hawaii` is the semantically most similar to the document about `pineapple`.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
{
'documents': [[
'This is a document about pineapple',
'This is a document about oranges'
]],
'ids': [['id1', 'id2']],
'distances': [[1.0404009819030762, 1.243080496788025]],
'uris': None,
'data': None,
'metadatas': [[None, None]],
'embeddings': None,
}
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
{
documents: [
[
'This is a document about pineapple',
'This is a document about oranges'
]
],
ids: [
['id1', 'id2']
],
distances: [[1.0404009819030762, 1.243080496788025]],
uris: null,
data: null,
metadatas: [[null, null]],
embeddings: null
}
```
{% /Tab %}

{% /TabbedCodeBlock %}

### 7. Try it out yourself

For example - what if we tried querying with `"This is a document about florida"`?

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
import chromadb
chroma_client = chromadb.Client()

# switch `create_collection` to `get_or_create_collection` to avoid creating a new collection every time
collection = chroma_client.get_or_create_collection(name="my_collection")

# switch `add` to `upsert` to avoid adding the same documents every time
collection.upsert(
documents=[
"This is a document about pineapple",
"This is a document about oranges"
],
ids=["id1", "id2"]
)

results = collection.query(
query_texts=["This is a query document about florida"], # Chroma will embed this for you
n_results=2 # how many results to return
)

print(results)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
import { ChromaClient } from "chromadb";
const client = new ChromaClient();

// switch `createCollection` to `getOrCreateCollection` to avoid creating a new collection every time
const collection = await client.getOrCreateCollection({
name: "my_collection",
});

// switch `addRecords` to `upsertRecords` to avoid adding the same documents every time
await collection.upsert({
documents: [
"This is a document about pineapple",
"This is a document about oranges",
],
ids: ["id1", "id2"],
});

const results = await collection.query({
queryTexts: "This is a query document about florida", // Chroma will embed this for you
nResults: 2, // how many results to return
});

console.log(results);
```
{% /Tab %}

{% /TabbedCodeBlock %}

## Next steps

- Learn how to [Deploy Chroma](../../production/deployment) to a server
- Join Chroma's [Discord Community](https://discord.com/invite/MMeYNTmh3x) to ask questions and get help
- Follow Chroma on [Twitter (@trychroma)](https://twitter.com/trychroma) for updates
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
{
"id": "introduction",
"title": "Introduction",
"section": "Overview",
"order": 0
}
---

# Chroma

**Chroma is the open-source AI application database**. Chroma makes it easy to build LLM apps by making knowledge, facts, and skills pluggable for LLMs.

{% Banner type="tip" %}
New to Chroma? Check out the [getting started guide](./getting-started)
{% /Banner %}

![Chroma Computer](/computer.svg)

Chroma gives you everything you need for retrieval:

- Store embeddings and their metadata
- Vector search
- Full-text search
- Document storage
- Metadata filtering
- Multi-modal retrieval

Chroma runs as a server and provides `Python` and `JavaScript/TypeScript` client SDKs. Check out the [Colab demo](https://colab.research.google.com/drive/1QEzFyqnoFxq7LUGyP1vzR4iLt9PpCDXv?usp=sharing) (yes, it can run in a Jupyter notebook).

Chroma is licensed under [Apache 2.0](https://github.com/chroma-core/chroma/blob/main/LICENSE)

### Python
In Python, Chroma can run in a python script or as a server. Install Chroma with

```shell
pip install chromadb
```

### JavaScript
In JavaScript, use the Chroma JS/TS Client to connect to a Chroma server. Install Chroma with your favorite package manager:

{% TabbedUseCaseCodeBlock language="Terminal" %}

{% Tab label="yarn" %}
```terminal
yarn install chromadb chromadb-default-embed
```
{% /Tab %}

{% Tab label="npm" %}
```terminal
npm install --save chromadb chromadb-default-embed
```
{% /Tab %}

{% Tab label="pnpm" %}
```terminal
pnpm install chromadb chromadb-default-embed
```
{% /Tab %}

{% /TabbedUseCaseCodeBlock %}


Continue with the full [getting started guide](./getting-started).


***

### Language Clients

| Language | Client |
|---------------|--------------------------------------------------------------------------------------------------------------------------|
| Python | [`chromadb`](https://pypistats.org/packages/chromadb) (by Chroma) |
| Javascript | [`chromadb`](https://www.npmjs.com/package/chromadb) (by Chroma) |
| Ruby | [from @mariochavez](https://github.com/mariochavez/chroma) |
| Java | [from @t_azarov](https://github.com/amikos-tech/chromadb-java-client) |
| Go | [from @t_azarov](https://github.com/amikos-tech/chroma-go) |
| C# | [from @microsoft](https://github.com/microsoft/semantic-kernel/tree/main/dotnet/src/Connectors/Connectors.Memory.Chroma) |
| Rust | [from @Anush008](https://crates.io/crates/chromadb) |
| Elixir | [from @3zcurdia](https://hex.pm/packages/chroma/) |
| Dart | [from @davidmigloz](https://pub.dev/packages/chromadb) |
| PHP | [from @CodeWithKyrian](https://github.com/CodeWithKyrian/chromadb-php) |
| PHP (Laravel) | [from @HelgeSverre](https://github.com/helgeSverre/chromadb) |
| Clojure | [from @levand](https://github.com/levand/clojure-chroma-client) |


{% br %}{% /br %}

We welcome [contributions](/markdoc/content/docs/overview/contributing.md) for other languages!

103 changes: 103 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/docs/overview/roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
{
"id": "roadmap",
"title": "Roadmap",
"section": "Overview",
"order": 2
}
---


# Roadmap


{% note type="default" title="Last Updated" %}
`May 20, 2024`
{% /note %}

The goal of this doc is to align *core* and *community* efforts for the project and to share what's in store for this year!

**Sections**
- What is the core Chroma team working on right now?
- What will Chroma prioritize over the next 6mo?
- What areas are great for community contributions?

## What is the core Chroma team working on right now?

- Standing up that distributed system as a managed service (aka "Hosted Chroma" - [sign up for waitlist](https://airtable.com/shrOAiDUtS2ILy5vZ)!)

## What did the Chroma team just complete?

Features like:
- *New* - [Chroma 0.4](https://www.trychroma.com/blog/chroma_0.4.0) - our first production-oriented release
- A more minimal python-client only build target
- Google PaLM embedding support
- OpenAI ChatGPT Retrieval Plugin

## What will Chroma prioritize over the next 6mo?

**Next Milestone: ☁️ Launch Hosted Chroma**

**Areas we will invest in**

Not an exhaustive list, but these are some of the core team’s biggest priorities over the coming few months. Use caution when contributing in these areas and please check-in with the core team first.

- **Workflow**: Building tools for answer questions like: what embedding model should I use? And how should I chunk up my documents?
- **Visualization**: Building visualization tool to give developers greater intuition embedding spaces
- **Query Planner**: Building tools to enable per-query and post-query transforms
- **Developer experience**: Extending Chroma into a CLI
- **Easier Data Sharing**: Working on formats for serialization and easier data sharing of embedding Collections
- **Improving recall**: Fine-tuning embedding transforms through human feedback
- **Analytical horsepower**: Clustering, deduplication, classification and more

## What areas are great for community contributions?

This is where you have a lot more free reign to contribute (without having to sync with us first)!

If you're unsure about your contribution idea, feel free to chat with us (@chroma) in the `#general` channel in [our Discord](https://discord.gg/rahcMUU5XV)! We'd love to support you however we can.

### Example Templates

We can always use [more integrations](../../integrations/chroma-integrations) with the rest of the AI ecosystem. Please let us know if you're working on one and need help!

Other great starting points for Chroma (please send PRs for more [here](https://github.com/chroma-core/docs/tree/swyx/addRoadmap/docs)):
- [Google Colab](https://colab.research.google.com/drive/1QEzFyqnoFxq7LUGyP1vzR4iLt9PpCDXv?usp=sharing)
- [Replit Template](https://replit.com/@swyx/BasicChromaStarter?v=1)

For those integrations we do have, like LangChain and LlamaIndex, we do always want more tutorials, demos, workshops, videos, and podcasts (we've done some pods [on our blog](https://trychroma.com/blog)).

### Example Datasets

It doesn’t make sense for developers to embed the same information over and over again with the same embedding model.

We'd like suggestions for:

- "small" (<100 rows)
- "medium" (<5MB)
- "large" (>1GB)

datasets for people to stress test Chroma in a variety of scenarios.

### Embeddings Comparison

Chroma does ship with Sentence Transformers by default for embeddings, but we are otherwise unopinionated about what embeddings you use. Having a library of information that has been embedded with many models, alongside example query sets would make it much easier for empirical work to be done on the effectiveness of various models across different domains.

- [Preliminary reading on Embeddings](https://towardsdatascience.com/neural-network-embeddings-explained-4d028e6f0526?gi=ee46baab0d8f)
- [Huggingface Benchmark of a bunch of Embeddings](https://huggingface.co/blog/mteb)
- [notable issues with GPT3 Embeddings](https://twitter.com/Nils_Reimers/status/1487014195568775173) and alternatives to consider

### Experimental Algorithms

If you have a research background, please consider adding to our `ExperimentalAPI`s. For example:

- Projections (t-sne, UMAP, the new hotness, the one you just wrote) and Lightweight visualization
- Clustering (HDBSCAN, PCA)
- Deduplication
- Multimodal (CLIP)
- Fine-tuning manifold with human feedback [eg](https://github.com/openai/openai-cookbook/blob/main/examples/Customizing_embeddings.ipynb)
- Expanded vector search (MMR, Polytope)
- Your research

You can find the REST OpenAPI spec at `localhost:8000/openapi.json` when the backend is running.

Please [reach out](https://discord.gg/MMeYNTmh3x) and talk to us before you get too far in your projects so that we can offer technical guidance/align on roadmap.
74 changes: 74 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/docs/overview/telemetry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Telemetry

Chroma contains a telemetry feature that collects **anonymous** usage information.

### Why?

We use this information to help us understand how Chroma is used, to help us prioritize work on new features and bug fixes, and to help us improve Chroma’s performance and stability.

### Opting out

If you prefer to opt out of telemetry, you can do this in two ways.

#### In Client Code

{% MarkdocTabs %}

{% Tab label="python" %}

Set `anonymized_telemetry` to `False` in your client's settings:

```python
from chromadb.config import Settings
client = chromadb.Client(Settings(anonymized_telemetry=False))
# or if using PersistentClient
client = chromadb.PersistentClient(path="/path/to/save/to", settings=Settings(anonymized_telemetry=False))
```

{% /Tab %}

{% Tab label="typescript" %}

Disable telemetry on you Chroma server (see next section).

{% /Tab %}

{% /MarkdocTabs %}

#### In Chroma's Backend Using Environment Variables

Set `ANONYMIZED_TELEMETRY` to `False` in your shell or server environment.

If you are running Chroma on your local computer with `docker-compose` you can set this value in an `.env` file placed in the same directory as the `docker-compose.yml` file:

```
ANONYMIZED_TELEMETRY=False
```

### What do you track?

We will only track usage details that help us make product decisions, specifically:

- Chroma version and environment details (e.g. OS, Python version, is it running in a container, or in a jupyter notebook)
- Usage of embedding functions that ship with Chroma and aggregated usage of custom embeddings (we collect no information about the custom embeddings themselves)
- Client interactions with our hosted Chroma Cloud service.
- Collection commands. We track the anonymized uuid of a collection as well as the number of items
- `add`
- `update`
- `query`
- `get`
- `delete`

We **do not** collect personally-identifiable or sensitive information, such as: usernames, hostnames, file names, environment variables, or hostnames of systems being tested.

To view the list of events we track, you may reference the **[code](https://github.com/chroma-core/chroma/blob/main/chromadb/telemetry/product/events.py)**

### Where is telemetry information stored?

We use **[Posthog](https://posthog.com/)** to store and visualize telemetry data.

{% Banner type="tip" %}

Posthog is an open source platform for product analytics. Learn more about Posthog on **[posthog.com](https://posthog.com/)** or **[github.com/posthog](https://github.com/posthog/posthog)**

{% /Banner %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Full Text Search

In order to filter on document contents, you must supply a `where_document` filter dictionary to the query. We support two filtering keys: `$contains` and `$not_contains`. The dictionary must have the following structure:

```python
# Filtering for a search_string
{
"$contains": "search_string"
}

# Filtering for not contains
{
"$not_contains": "search_string"
}
```

You can combine full-text search with Chroma's metadata filtering.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.query(
query_texts=["doc10", "thus spake zarathustra", ...],
n_results=10,
where={"metadata_field": "is_equal_to_this"},
where_document={"$contains":"search_string"}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.query({
queryTexts: ["doc10", "thus spake zarathustra", ...],
nResults: 10,
where: {"metadata_field": "is_equal_to_this"},
whereDocument: {"$contains": "search_string"}
})
```
{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Metadata Filtering

Chroma supports filtering queries by `metadata` and `document` contents. The `where` filter is used to filter by `metadata`.

In order to filter on metadata, you must supply a `where` filter dictionary to the query. The dictionary must have the following structure:

```python
{
"metadata_field": {
<Operator>: <Value>
}
}
```

Filtering metadata supports the following operators:

- `$eq` - equal to (string, int, float)
- `$ne` - not equal to (string, int, float)
- `$gt` - greater than (int, float)
- `$gte` - greater than or equal to (int, float)
- `$lt` - less than (int, float)
- `$lte` - less than or equal to (int, float)

Using the `$eq` operator is equivalent to using the `where` filter.

```python
{
"metadata_field": "search_string"
}

# is equivalent to

{
"metadata_field": {
"$eq": "search_string"
}
}
```

{% Banner type="note" %}
Where filters only search embeddings where the key exists. If you search `collection.get(where={"version": {"$ne": 1}})`. Metadata that does not have the key `version` will not be returned.
{% /Banner %}

#### Using logical operators

You can also use the logical operators `$and` and `$or` to combine multiple filters.

An `$and` operator will return results that match all of the filters in the list.

```python
{
"$and": [
{
"metadata_field": {
<Operator>: <Value>
}
},
{
"metadata_field": {
<Operator>: <Value>
}
}
]
}
```

An `$or` operator will return results that match any of the filters in the list.

```python
{
"$or": [
{
"metadata_field": {
<Operator>: <Value>
}
},
{
"metadata_field": {
<Operator>: <Value>
}
}
]
}
```

#### Using inclusion operators (`$in` and `$nin`)

The following inclusion operators are supported:

- `$in` - a value is in predefined list (string, int, float, bool)
- `$nin` - a value is not in predefined list (string, int, float, bool)

An `$in` operator will return results where the metadata attribute is part of a provided list:

```json
{
"metadata_field": {
"$in": ["value1", "value2", "value3"]
}
}
```

An `$nin` operator will return results where the metadata attribute is not part of a provided list:

```json
{
"metadata_field": {
"$nin": ["value1", "value2", "value3"]
}
}
```

{% Banner type="tip" %}

For additional examples and a demo how to use the inclusion operators, please see provided notebook [here](https://github.com/chroma-core/chroma/blob/main/examples/basic_functionality/in_not_in_filtering.ipynb)

{% /Banner %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Query and Get Data from Chroma Collections

Chroma collections can be queried in a variety of ways, using the `.query` method.

You can query by a set of `query embeddings`.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.query(
query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
n_results=10,
where={"metadata_field": "is_equal_to_this"},
where_document={"$contains":"search_string"}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
const result = await collection.query({
queryEmbeddings: [[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
nResults: 10,
where: {"metadata_field": "is_equal_to_this"},
})
```
{% /Tab %}

{% /TabbedCodeBlock %}

The query will return the `n results` closest matches to each `query embedding`, in order.
An optional `where` filter dictionary can be supplied to filter by the `metadata` associated with each document.
Additionally, an optional `where document` filter dictionary can be supplied to filter by contents of the document.

If the supplied `query embeddings` are not the same dimension as the collection, an exception will be raised.

You can also query by a set of `query texts`. Chroma will first embed each `query text` with the collection's embedding function, and then perform the query with the generated embedding.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.query(
query_texts=["doc10", "thus spake zarathustra", ...],
n_results=10,
where={"metadata_field": "is_equal_to_this"},
where_document={"$contains":"search_string"}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.query({
queryTexts: ["doc10", "thus spake zarathustra", ...],
nResults: 10,
where: {"metadata_field": "is_equal_to_this"},
whereDocument: {"$contains": "search_string"}
})
```
{% /Tab %}

{% /TabbedCodeBlock %}

You can also retrieve items from a collection by `id` using `.get`.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
collection.get(
ids=["id1", "id2", "id3", ...],
where={"style": "style1"}
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await collection.get( {
ids: ["id1", "id2", "id3", ...],
where: {"style": "style1"}
})
```
{% /Tab %}

{% /TabbedCodeBlock %}

`.get` also supports the `where` and `where document` filters. If no `ids` are supplied, it will return all items in the collection that match the `where` and `where document` filters.

### Choosing Which Data is Returned

When using get or query you can use the `include` parameter to specify which data you want returned - any of `embeddings`, `documents`, `metadatas`, and for query, `distances`. By default, Chroma will return the `documents`, `metadatas` and in the case of query, the `distances` of the results. `embeddings` are excluded by default for performance and the `ids` are always returned. You can specify which of these you want returned by passing an array of included field names to the includes parameter of the query or get method. Note that embeddings will be returned as a 2-d numpy array in `.get` and a python list of 2-d numpy arrays in `.query`.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
# Only get documents and ids
collection.get(
include=["documents"]
)

collection.query(
query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
include=["documents"]
)
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
// Only get documents and ids
await collection.get({
include: ["documents"]
})

await collection.query({
query_embeddings: [[11.1, 12.1, 13.1], [1.1, 2.3, 3.2], ...],
include: ["documents"]
})
```
{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Running Chroma in Client-Server Mode

Chroma can also be configured to run in client/server mode. In this mode, the Chroma client connects to a Chroma server running in a separate process.

To start the Chroma server, run the following command:

```terminal
chroma run --path /db_path
```

{% MarkdocTabs %}

{% Tab label="python" %}

Then use the Chroma HTTP client to connect to the server:

```python
import chromadb

chroma_client = chromadb.HttpClient(host='localhost', port=8000)
```

That's it! Chroma's API will run in `client-server` mode with just this change.

Chroma also provides an async HTTP client. The behaviors and method signatures are identical to the synchronous client, but all methods that would block are now async. To use it, call `AsyncHttpClient` instead:

```python
import asyncio
import chromadb

async def main():
client = await chromadb.AsyncHttpClient()

collection = await client.create_collection(name="my_collection")
await collection.add(
documents=["hello world"],
ids=["id1"]
)

asyncio.run(main())
```

If you [deploy](../../production/deployment) your Chroma server, you can also use our [http-only](./python-http-client) package.

{% /Tab %}

{% Tab label="typescript" %}

Then you can connect to it by instantiating a new `ChromaClient`:

```typescript
import { ChromaClient } from "chromadb";

const client = new ChromaClient();
```

{% /Tab %}

{% /MarkdocTabs %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Ephemeral Client

In Python, you can run a Chroma server in-memory and connect to it with the ephemeral client:

```python
import chromadb

client = chromadb.Client()
```

This is a great tool for experimenting with different embedding functions and retrieval techniques in a Python notebook, for example.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Persistent Client

{% MarkdocTabs %}

{% Tab label="python" %}

You can configure Chroma to save and load the database from your local machine, using the `PersistentClient`.

Data will be persisted automatically and loaded on start (if it exists).

```python
import chromadb

client = chromadb.PersistentClient(path="/path/to/save/to")
```

The `path` is where Chroma will store its database files on disk, and load them on start.

{% /Tab %}

{% Tab label="typescript" %}

To connect with the JS/TS client, you must connect to a Chroma server.

To run a Chroma server locally that will persist your data, install Chroma via `pip`:

```terminal
pip install chromadb
```

And run the server using our CLI:

```terminal
chroma run --path ./getting-started
```

The `path` is where Chroma will store its database files on disk, and load them on start.

Alternatively, you can also use our official Docker image:

```terminal
docker pull chromadb/chroma
docker run -p 8000:8000 chromadb/chroma
```

With a Chroma server running locally, you can connect to it by instantiating a new `ChromaClient`:

```typescript
import { ChromaClient } from "chromadb";

const client = new ChromaClient();
```

See [Running Chroma in client-server mode](../client-server-mode) for more.

{% /Tab %}

{% /MarkdocTabs %}

The client object has a few useful convenience methods.

{% TabbedCodeBlock %}

{% Tab label="python" %}
```python
client.heartbeat() # returns a nanosecond heartbeat. Useful for making sure the client remains connected.
client.reset() # Empties and completely resets the database. ⚠️ This is destructive and not reversible.
```
{% /Tab %}

{% Tab label="typescript" %}
```typescript
await client.heartbeat(); // returns a nanosecond heartbeat. Useful for making sure the client remains connected.
await client.reset(); // Empties and completely resets the database. ⚠️ This is destructive and not reversible.
```
{% /Tab %}

{% /TabbedCodeBlock %}

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The Python HTTP-Only Client

If you are running Chroma in client-server mode, you may not need the full Chroma library. Instead, you can use the lightweight client-only library.
In this case, you can install the `chromadb-client` package. This package is a lightweight HTTP client for the server with a minimal dependency footprint.

```terminal
pip install chromadb-client
```

```python
import chromadb
# Example setup of the client to connect to your chroma server
client = chromadb.HttpClient(host='localhost', port=8000)

# Or for async usage:
async def main():
client = await chromadb.AsyncHttpClient(host='localhost', port=8000)
```

Note that the `chromadb-client` package is a subset of the full Chroma library and does not include all the dependencies. If you want to use the full Chroma library, you can install the `chromadb` package instead.
Most importantly, there is no default embedding function. If you add() documents without embeddings, you must have manually specified an embedding function and installed the dependencies for it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Integrations

### Embedding Integrations

Embeddings are the A.I-native way to represent any kind of data, making them the perfect fit for working with all kinds of A.I-powered tools and algorithms. They can represent text, images, and soon audio and video. There are many options for creating embeddings, whether locally using an installed library, or by calling an API.

Chroma provides lightweight wrappers around popular embedding providers, making it easy to use them in your apps. You can set an embedding function when you create a Chroma collection, which will be used automatically, or you can call them directly yourself.

{% special_table %}
{% /special_table %}

| | Python | Typescript |
|-------------------------------------------------------------------------|--|------------|
| [OpenAI](./embedding-models/openai) |||
| [Google Gemini](./embedding-models/google-gemini) |||
| [Cohere](./embedding-models/cohere) |||
| [Hugging Face](./embedding-models/hugging-face) || - |
| [Instructor](./embedding-models/instructor) || - |
| [Hugging Face Embedding Server](./embedding-models/hugging-face-server) |||
| [Jina AI](./embedding-models/jina-ai) |||
| [Roboflow](./embedding-models/roboflow) || - |
| [Ollama Embeddings](./embedding-models/ollama) |||


***

### Framework Integrations

Chroma maintains integrations with many popular tools. These tools can be used to define the business logic of an AI-native application, curate data, fine-tune embedding spaces and more.

We welcome pull requests to add new Integrations to the community.

{% special_table %}
{% /special_table %}

| | Python | JS |
|---------------------------------------|----|--------------|
| [Langchain](./frameworks/langchain) |||
| [LlamaIndex](./frameworks/llamaindex) |||
| [Braintrust](./frameworks/braintrust) |||
| [OpenLLMetry](./frameworks/openllmetry) || Coming Soon! |
| [Streamlit](./frameworks/streamlit) || - |
| [Haystack](./frameworks/haystack) || - |
| [OpenLIT](./frameworks/openlit) || Coming Soon! |
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
id: 'cohere'
name: 'Cohere'
---

# Cohere

Chroma also provides a convenient wrapper around Cohere's embedding API. This embedding function runs remotely on Cohere’s servers, and requires an API key. You can get an API key by signing up for an account at [Cohere](https://dashboard.cohere.ai/welcome/register).

{% MarkdocTabs %}
{% Tab label="python" %}

This embedding function relies on the `cohere` python package, which you can install with `pip install cohere`.

```python
import chromadb.utils.embedding_functions as embedding_functions
cohere_ef = embedding_functions.CohereEmbeddingFunction(api_key="YOUR_API_KEY", model_name="large")
cohere_ef(texts=["document1","document2"])
```

{% /Tab %}

{% Tab label="typescript" %}

```typescript
import { CohereEmbeddingFunction } from 'chromadb';

const embedder = new CohereEmbeddingFunction("apiKey")

// use directly
const embeddings = embedder.generate(["document1","document2"])

// pass documents to query for .add and .query
const collection = await client.createCollection({name: "name", embeddingFunction: embedder})
const collectionGet = await client.getCollection({name:"name", embeddingFunction: embedder})
```

{% /Tab %}

{% /MarkdocTabs %}

You can pass in an optional `model_name` argument, which lets you choose which Cohere embeddings model to use. By default, Chroma uses `large` model. You can see the available models under `Get embeddings` section [here](https://docs.cohere.ai/reference/embed).

### Multilingual model example

{% TabbedCodeBlock %}

{% Tab label="python" %}

```python
cohere_ef = embedding_functions.CohereEmbeddingFunction(
api_key="YOUR_API_KEY",
model_name="multilingual-22-12")

multilingual_texts = [ 'Hello from Cohere!', 'مرحبًا من كوهير!',
'Hallo von Cohere!', 'Bonjour de Cohere!',
'¡Hola desde Cohere!', 'Olá do Cohere!',
'Ciao da Cohere!', '您好,来自 Cohere!',
'कोहिअर से नमस्ते!' ]

cohere_ef(texts=multilingual_texts)

```

{% /Tab %}

{% Tab label="typescript" %}

```typescript
import { CohereEmbeddingFunction } from 'chromadb';

const embedder = new CohereEmbeddingFunction("apiKey")

multilingual_texts = [ 'Hello from Cohere!', 'مرحبًا من كوهير!',
'Hallo von Cohere!', 'Bonjour de Cohere!',
'¡Hola desde Cohere!', 'Olá do Cohere!',
'Ciao da Cohere!', '您好,来自 Cohere!',
'कोहिअर से नमस्ते!' ]

const embeddings = embedder.generate(multilingual_texts)

```

{% /Tab %}

{% /TabbedCodeBlock %}

For more information on multilingual model you can read [here](https://docs.cohere.ai/docs/multilingual-language-models).
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
id: google-gemini
name: "Google Gemini"
---

# Google Gemini

Chroma provides a convenient wrapper around Google's Generative AI embedding API. This embedding function runs remotely on Google's servers, and requires an API key.

You can get an API key by signing up for an account at [Google MakerSuite](https://makersuite.google.com/).

{% MarkdocTabs %}

{% Tab label="python" %}

This embedding function relies on the `google-generativeai` python package, which you can install with `pip install google-generativeai`.

```python
# import
import chromadb.utils.embedding_functions as embedding_functions

# use directly
google_ef = embedding_functions.GoogleGenerativeAiEmbeddingFunction(api_key="YOUR_API_KEY")
google_ef(["document1","document2"])

# pass documents to query for .add and .query
collection = client.create_collection(name="name", embedding_function=google_ef)
collection = client.get_collection(name="name", embedding_function=google_ef)
```

You can view a more [complete example](https://github.com/chroma-core/chroma/tree/main/examples/gemini) chatting over documents with Gemini embedding and langauge models.

For more info - please visit the [official Google python docs](https://ai.google.dev/tutorials/python_quickstart).

{% /Tab %}

{% Tab label="typescript" %}

This embedding function relies on the `@google/generative-ai` npm package, which you can install with e.g. `npm install @google/generative-ai`.

```typescript
import { ChromaClient, GoogleGenerativeAiEmbeddingFunction } from "chromadb";
const embedder = new GoogleGenerativeAiEmbeddingFunction({
googleApiKey: "<YOUR API KEY>",
});

// use directly
const embeddings = await embedder.generate(["document1", "document2"]);

// pass documents to query for .add and .query
const collection = await client.createCollection({
name: "name",
embeddingFunction: embedder,
});
const collectionGet = await client.getCollection({
name: "name",
embeddingFunction: embedder,
});
```

You can view a more [complete example using Node](https://github.com/chroma-core/chroma/blob/main/clients/js/examples/node/app.js).

For more info - please visit the [official Google JS docs](https://ai.google.dev/tutorials/node_quickstart).

{% /Tab %}

{% /MarkdocTabs %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
id: hugging-face-server
name: 'Hugging Face Server'
---

# Hugging Face Server

Chroma provides a convenient wrapper for HuggingFace Text Embedding Server, a standalone server that provides text embeddings via a REST API. You can read more about it [**here**](https://github.com/huggingface/text-embeddings-inference).

## Setting Up The Server

To run the embedding server locally you can run the following command from the root of the Chroma repository. The docker compose command will run Chroma and the embedding server together.

```terminal
docker compose -f examples/server_side_embeddings/huggingface/docker-compose.yml up -d
```

or

```terminal
docker run -p 8001:80 -d -rm --name huggingface-embedding-server ghcr.io/huggingface/text-embeddings-inference:cpu-0.3.0 --model-id BAAI/bge-small-en-v1.5 --revision -main
```

{% Banner type="note" %}
The above docker command will run the server with the `BAAI/bge-small-en-v1.5` model. You can find more information about running the server in docker [**here**](https://github.com/huggingface/text-embeddings-inference#docker).
{% /Banner %}

## Usage

{% TabbedCodeBlock %}

{% Tab label="python" %}

```python
from chromadb.utils.embedding_functions import HuggingFaceEmbeddingServer
huggingface_ef = HuggingFaceEmbeddingServer(url="http://localhost:8001/embed")
```

{% /Tab %}

{% Tab label="typescript" %}


```typescript
import {HuggingFaceEmbeddingServerFunction} from 'chromadb';
const embedder = new HuggingFaceEmbeddingServerFunction({url:"http://localhost:8001/embed"})

// use directly
const embeddings = embedder.generate(["document1","document2"])

// pass documents to query for .add and .query
let collection = await client.createCollection({name: "name", embeddingFunction: embedder})
collection = await client.getCollection({name: "name", embeddingFunction: embedder})
```

{% /Tab %}
{% /TabbedCodeBlock %}

The embedding model is configured on the server side. Check the docker-compose file in `examples/server_side_embeddings/huggingface/docker-compose.yml` for an example of how to configure the server.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
id: hugging-face
name: Hugging Face
---

# Hugging Face

Chroma also provides a convenient wrapper around HuggingFace's embedding API. This embedding function runs remotely on HuggingFace's servers, and requires an API key. You can get an API key by signing up for an account at [HuggingFace](https://huggingface.co/).

{% tabs group="code-lang" hideTabs=true %}
{% tab label="Python" %}

```python
import chromadb.utils.embedding_functions as embedding_functions
huggingface_ef = embedding_functions.HuggingFaceEmbeddingFunction(
api_key="YOUR_API_KEY",
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
```

You can pass in an optional `model_name` argument, which lets you choose which HuggingFace model to use. By default, Chroma uses `sentence-transformers/all-MiniLM-L6-v2`. You can see a list of all available models [here](https://huggingface.co/models).

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
id: instructor
name: Instructor
---

# Instructor

The [instructor-embeddings](https://github.com/HKUNLP/instructor-embedding) library is another option, especially when running on a machine with a cuda-capable GPU. They are a good local alternative to OpenAI (see the [Massive Text Embedding Benchmark](https://huggingface.co/blog/mteb) rankings). The embedding function requires the InstructorEmbedding package. To install it, run ```pip install InstructorEmbedding```.

There are three models available. The default is `hkunlp/instructor-base`, and for better performance you can use `hkunlp/instructor-large` or `hkunlp/instructor-xl`. You can also specify whether to use `cpu` (default) or `cuda`. For example:

```python
#uses base model and cpu
import chromadb.utils.embedding_functions as embedding_functions
ef = embedding_functions.InstructorEmbeddingFunction()
```
or
```python
import chromadb.utils.embedding_functions as embedding_functions
ef = embedding_functions.InstructorEmbeddingFunction(
model_name="hkunlp/instructor-xl", device="cuda")
```
Keep in mind that the large and xl models are 1.5GB and 5GB respectively, and are best suited to running on a GPU.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
id: jina-ai
name: Jina AI
---

# JinaAI

Chroma provides a convenient wrapper around JinaAI's embedding API. This embedding function runs remotely on JinaAI's servers, and requires an API key. You can get an API key by signing up for an account at [JinaAI](https://jina.ai/embeddings/).

{% TabbedCodeBlock %}

{% Tab label="python" %}

```python
import chromadb.utils.embedding_functions as embedding_functions
jinaai_ef = embedding_functions.JinaEmbeddingFunction(
api_key="YOUR_API_KEY",
model_name="jina-embeddings-v2-base-en"
)
jinaai_ef(input=["This is my first text to embed", "This is my second document"])
```

{% /Tab %}

{% Tab label="typescript" %}

```typescript
import { JinaEmbeddingFunction } from 'chromadb';

const embedder = new JinaEmbeddingFunction({
jinaai_api_key: 'jina_****',
model_name: 'jina-embeddings-v2-base-en',
});

// use directly
const embeddings = embedder.generate(['document1', 'document2']);

// pass documents to query for .add and .query
const collection = await client.createCollection({name: "name", embeddingFunction: embedder})
const collectionGet = await client.getCollection({name:"name", embeddingFunction: embedder})
```

{% /Tab %}

{% /TabbedCodeBlock %}

You can pass in an optional `model_name` argument, which lets you choose which Jina model to use. By default, Chroma uses `jina-embedding-v2-base-en`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
id: ollama
name: Ollama
---

# Ollama

Chroma provides a convenient wrapper around [Ollama](https://github.com/ollama/ollama)'
s [embeddings API](https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings). You can use
the `OllamaEmbeddingFunction` embedding function to generate embeddings for your documents with
a [model](https://github.com/ollama/ollama?tab=readme-ov-file#model-library) of your choice.

{% TabbedCodeBlock %}

{% Tab label="python" %}

```python
import chromadb.utils.embedding_functions as embedding_functions

ollama_ef = embedding_functions.OllamaEmbeddingFunction(
url="http://localhost:11434/api/embeddings",
model_name="llama2",
)

embeddings = ollama_ef(["This is my first text to embed",
"This is my second document"])
```

{% /Tab %}

{% Tab label="typescript" %}

```typescript
import { OllamaEmbeddingFunction } from "chromadb";
const embedder = new OllamaEmbeddingFunction({
url: "http://127.0.0.1:11434/api/embeddings",
model: "llama2"
})

// use directly
const embeddings = embedder.generate(["document1", "document2"])

// pass documents to query for .add and .query
let collection = await client.createCollection({
name: "name",
embeddingFunction: embedder
})
collection = await client.getCollection({
name: "name",
embeddingFunction: embedder
})
```

{% /Tab %}

{% /TabbedCodeBlock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
name: OpenAI
id: openai
---

# OpenAI

Chroma provides a convenient wrapper around OpenAI's embedding API. This embedding function runs remotely on OpenAI's servers, and requires an API key. You can get an API key by signing up for an account at [OpenAI](https://openai.com/api/).

The following OpenAI Embedding Models are supported:

- `text-embedding-ada-002`
- `text-embedding-3-small`
- `text-embedding-3-large`

{% Banner type="tip" %}
Visit OpenAI Embeddings [documentation](https://platform.openai.com/docs/guides/embeddings) for more information.
{% /Banner %}

{% MarkdocTabs %}

{% Tab label="python" %}

This embedding function relies on the `openai` python package, which you can install with `pip install openai`.

You can pass in an optional `model_name` argument, which lets you choose which OpenAI embeddings model to use. By default, Chroma uses `text-embedding-ada-002`.

```python
import chromadb.utils.embedding_functions as embedding_functions
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="YOUR_API_KEY",
model_name="text-embedding-3-small"
)
```

To use the OpenAI embedding models on other platforms such as Azure, you can use the `api_base` and `api_type` parameters:
```python
import chromadb.utils.embedding_functions as embedding_functions
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="YOUR_API_KEY",
api_base="YOUR_API_BASE_PATH",
api_type="azure",
api_version="YOUR_API_VERSION",
model_name="text-embedding-3-small"
)
```

{% /Tab %}

{% Tab label="typescript" %}

You can pass in an optional `model` argument, which lets you choose which OpenAI embeddings model to use. By default, Chroma uses `text-embedding-ada-002`.

```typescript
import { OpenAIEmbeddingFunction } from 'chromadb';

const embeddingFunction = new OpenAIEmbeddingFunction({
openai_api_key: "apiKey",
model: "text-embedding-3-small"
})

// use directly
const embeddings = embeddingFunction.generate(["document1","document2"])

// pass documents to query for .add and .query
let collection = await client.createCollection({
name: "name",
embeddingFunction: embeddingFunction
})
collection = await client.getCollection({
name: "name",
embeddingFunction: embeddingFunction
})
```

{% /Tab %}

{% /MarkdocTabs %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
id: 'roboflow'
name: Roboflow
---

# Roboflow

You can use [Roboflow Inference](https://inference.roboflow.com) with Chroma to calculate multi-modal text and image embeddings with CLIP. through the `RoboflowEmbeddingFunction` class. Inference can be used through the Roboflow cloud, or run on your hardware.

## Roboflow Cloud Inference

To run Inference through the Roboflow cloud, you will need an API key. [Learn how to retrieve a Roboflow API key](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key).

You can pass it directly on creation of the `RoboflowEmbeddingFunction`:

```python
from chromadb.utils.embedding_functions import RoboflowEmbeddingFunction

roboflow_ef = RoboflowEmbeddingFunction(api_key=API_KEY)
```

Alternatively, you can set your API key as an environment variable:

```terminal
export ROBOFLOW_API_KEY=YOUR_API_KEY
```

Then, you can create the `RoboflowEmbeddingFunction` without passing an API key directly:

```python
from chromadb.utils.embedding_functions import RoboflowEmbeddingFunction

roboflow_ef = RoboflowEmbeddingFunction()
```

## Local Inference

You can run Inference on your own hardware.

To install Inference, you will need Docker installed. Follow the [official Docker installation instructions](https://docs.docker.com/engine/install/) for guidance on how to install Docker on the device on which you are working.

Then, you can install Inference with pip:

```terminal
pip install inference inference-cli
```

With Inference installed, you can start an Inference server. This server will run in the background. The server will accept HTTP requests from the `RoboflowEmbeddingFunction` to calculate CLIP text and image embeddings for use in your application:

To start an Inference server, run:

```terminal
inference server start
```

Your Inference server will run at `http://localhost:9001`.

Then, you can create the `RoboflowEmbeddingFunction`:

```python
from chromadb.utils.embedding_functions import RoboflowEmbeddingFunction

roboflow_ef = RoboflowEmbeddingFunction(api_key=API_KEY, server_url="http://localhost:9001")
```

This function will calculate embeddings using your local Inference server instead of the Roboflow cloud.

For a full tutorial on using Roboflow Inference with Chroma, refer to the [Roboflow Chroma integration tutorial](https://github.com/chroma-core/chroma/blob/main/examples/use_with/roboflow/embeddings.ipynb).
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
id: braintrust
name: Braintrust
---

# Braintrust

[Braintrust](https://www.braintrustdata.com) is an enterprise-grade stack for building AI products including: evaluations, prompt playground, dataset management, tracing, etc.

Braintrust provides a Typescript and Python library to run and log evaluations and integrates well with Chroma.

- [Tutorial: Evaluate Chroma Retrieval app w/ Braintrust](https://www.braintrustdata.com/docs/examples/rag)

Example evaluation script in Python:
(refer to the tutorial above to get the full implementation)
```python
from autoevals.llm import *
from braintrust import Eval

PROJECT_NAME="Chroma_Eval"

from openai import OpenAI

client = OpenAI()
leven_evaluator = LevenshteinScorer()

async def pipeline_a(input, hooks=None):
# Get a relevant fact from Chroma
relevant = collection.query(
query_texts=[input],
n_results=1,
)
relevant_text = ','.join(relevant["documents"][0])
prompt = """
You are an assistant called BT. Help the user.
Relevant information: {relevant}
Question: {question}
Answer:
""".format(question=input, relevant=relevant_text)
messages = [{"role": "system", "content": prompt}]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
temperature=0,
max_tokens=100,
)

result = response.choices[0].message.content
return result

# Run an evaluation and log to Braintrust
await Eval(
PROJECT_NAME,
# define your test cases
data = lambda:[{"input": "What is my eye color?", "expected": "Brown"}],
# define your retrieval pipeline w/ Chroma above
task = pipeline_a,
# use a prebuilt scoring function or define your own :)
scores=[leven_evaluator],
)
```

Learn more: [docs](https://www.braintrustdata.com/docs).
49 changes: 49 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/production/deployment.md
272 changes: 272 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/reference/js/client.md
274 changes: 274 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/reference/js/collection.md
507 changes: 507 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/reference/python/client.md
218 changes: 218 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/reference/python/collection.md
191 changes: 191 additions & 0 deletions docs/docs.trychroma.com/markdoc/content/sidebar-config.ts
16 changes: 0 additions & 16 deletions docs/docs.trychroma.com/markdoc/functions.ts

This file was deleted.

21 changes: 0 additions & 21 deletions docs/docs.trychroma.com/markdoc/nodes/fence.markdoc.tsx

This file was deleted.

31 changes: 0 additions & 31 deletions docs/docs.trychroma.com/markdoc/nodes/heading.markdoc.ts

This file was deleted.

4 changes: 0 additions & 4 deletions docs/docs.trychroma.com/markdoc/nodes/index.ts

This file was deleted.

9 changes: 0 additions & 9 deletions docs/docs.trychroma.com/markdoc/nodes/link.markdoc.ts

This file was deleted.

1 change: 0 additions & 1 deletion docs/docs.trychroma.com/markdoc/partials/header.md

This file was deleted.

34 changes: 0 additions & 34 deletions docs/docs.trychroma.com/markdoc/tags/codetabs.markdoc.ts

This file was deleted.

5 changes: 0 additions & 5 deletions docs/docs.trychroma.com/markdoc/tags/index.ts

This file was deleted.

28 changes: 0 additions & 28 deletions docs/docs.trychroma.com/markdoc/tags/note.markdoc.ts

This file was deleted.

10 changes: 0 additions & 10 deletions docs/docs.trychroma.com/markdoc/tags/special_table.markdoc.ts

This file was deleted.

36 changes: 0 additions & 36 deletions docs/docs.trychroma.com/markdoc/tags/tabs.markdoc.ts

This file was deleted.

59 changes: 59 additions & 0 deletions docs/docs.trychroma.com/middleware.ts
2 changes: 1 addition & 1 deletion docs/docs.trychroma.com/next-env.d.ts
6 changes: 0 additions & 6 deletions docs/docs.trychroma.com/next.config.js

This file was deleted.

19 changes: 19 additions & 0 deletions docs/docs.trychroma.com/next.config.mjs
35 changes: 27 additions & 8 deletions docs/docs.trychroma.com/package.json
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
11 changes: 11 additions & 0 deletions docs/docs.trychroma.com/public/chroma-wordmark-white-128.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions docs/docs.trychroma.com/public/chroma-workmark-color-128.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
745 changes: 745 additions & 0 deletions docs/docs.trychroma.com/public/computer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Binary file not shown.
Binary file not shown.
7 changes: 0 additions & 7 deletions docs/docs.trychroma.com/public/img/chroma.svg

This file was deleted.

Binary file not shown.
56 changes: 0 additions & 56 deletions docs/docs.trychroma.com/public/img/hrm4.svg

This file was deleted.

Binary file not shown.
4 changes: 0 additions & 4 deletions docs/docs.trychroma.com/public/img/svg_fast.svg

This file was deleted.

11 changes: 0 additions & 11 deletions docs/docs.trychroma.com/public/img/svg_fast2.svg

This file was deleted.

4 changes: 0 additions & 4 deletions docs/docs.trychroma.com/public/img/svg_feature.svg

This file was deleted.

196 changes: 0 additions & 196 deletions docs/docs.trychroma.com/public/img/svg_free.svg

This file was deleted.

14 changes: 0 additions & 14 deletions docs/docs.trychroma.com/public/img/svg_simple.svg

This file was deleted.

8 changes: 0 additions & 8 deletions docs/docs.trychroma.com/public/img/svg_simple2.svg

This file was deleted.

File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
1 change: 1 addition & 0 deletions docs/docs.trychroma.com/public/python.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
1 change: 1 addition & 0 deletions docs/docs.trychroma.com/public/typescript.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/docs.trychroma.com/public/x-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/docs.trychroma.com/pydoc-markdown.yml
2 changes: 1 addition & 1 deletion docs/docs.trychroma.com/scripts/jsDocs.sh
4 changes: 2 additions & 2 deletions docs/docs.trychroma.com/scripts/pythonDocs.sh
81 changes: 0 additions & 81 deletions docs/docs.trychroma.com/tailwind.config.js

This file was deleted.

29 changes: 29 additions & 0 deletions docs/docs.trychroma.com/tailwind.config.ts
24 changes: 16 additions & 8 deletions docs/docs.trychroma.com/tsconfig.json