From 30fbd06bb12980775e830b78c7d86cc41d7e8dac Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 31 Oct 2022 12:42:34 -0700 Subject: [PATCH 01/22] black python formatting --- Makefile | 5 + chroma-client/src/chroma_client/client.py | 136 ++++++++++-------- chroma-client/tests/test_client.py | 6 +- .../algorithms/rand_subsample.py | 4 +- .../algorithms/stub_distances.py | 13 +- chroma-server/chroma_server/api.py | 71 ++++----- chroma-server/chroma_server/db/abstract.py | 5 +- chroma-server/chroma_server/db/duckdb.py | 126 ++++++++++------ chroma-server/chroma_server/index/abstract.py | 5 +- chroma-server/chroma_server/index/hnswlib.py | 30 ++-- chroma-server/chroma_server/test/test_api.py | 92 ++++++++---- chroma-server/chroma_server/types/__init__.py | 3 +- chroma-server/chroma_server/utils.py | 4 +- pyproject.toml | 8 ++ 14 files changed, 317 insertions(+), 191 deletions(-) create mode 100644 Makefile create mode 100644 pyproject.toml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..75e62a2 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +black: + black --fast chroma-server chroma-client + +check_black: + black --check --fast chroma-server chroma-client \ No newline at end of file diff --git a/chroma-client/src/chroma_client/client.py b/chroma-client/src/chroma_client/client.py index 4089eab..6e6e8e4 100644 --- a/chroma-client/src/chroma_client/client.py +++ b/chroma-client/src/chroma_client/client.py @@ -2,6 +2,7 @@ import requests import json from typing import Union + class Chroma: _api_url = "http://localhost:8000/api/v1" @@ -15,127 +16,142 @@ class Chroma: self.url = url def count(self): - ''' + """ Returns the number of embeddings in the database - ''' + """ x = requests.get(self._api_url + "/count") return x.json() def fetch(self, where_filter={}, sort=None, limit=None): - ''' + """ Fetches embeddings from the database - ''' - x = requests.get(self._api_url + "/fetch", data=json.dumps({ - "where_filter":json.dumps(where_filter), - "sort":sort, - "limit":limit - })) + """ + x = requests.get( + self._api_url + "/fetch", + data=json.dumps( + {"where_filter": json.dumps(where_filter), "sort": sort, "limit": limit} + ), + ) return x.json() def process(self): - ''' + """ Processes embeddings in the database - currently this only runs hnswlib, doesnt return anything - ''' + """ requests.get(self._api_url + "/process") return True def reset(self): - ''' + """ Resets the database - ''' + """ return requests.get(self._api_url + "/reset") def persist(self): - ''' + """ Persists the database to disk in the .chroma folder inside chroma-server - ''' + """ return requests.get(self._api_url + "/persist") def rand(self): - ''' + """ Stubbed out sampling endpoint, returns a random bisection of the database - ''' + """ x = requests.get(self._api_url + "/rand") return x.json() def heartbeat(self): - ''' + """ Returns the current server time in milliseconds to check if the server is alive - ''' + """ x = requests.get(self._api_url) return x.json() - def log(self, - embedding_data: list, - input_uri: list, + def log( + self, + embedding_data: list, + input_uri: list, dataset: list = None, - category_name: list = None): - ''' + category_name: list = None, + ): + """ Logs a batch of embeddings to the database - pass in column oriented data lists - ''' + """ - x = requests.post(self._api_url + "/add", data = json.dumps({ - "embedding_data": embedding_data, - "input_uri": input_uri, - "dataset": dataset, - "category_name": category_name - }) ) + x = requests.post( + self._api_url + "/add", + data=json.dumps( + { + "embedding_data": embedding_data, + "input_uri": input_uri, + "dataset": dataset, + "category_name": category_name, + } + ), + ) if x.status_code == 201: return True else: return False - + def log_training(self, embedding_data: list, input_uri: list, category_name: list): - ''' + """ Small wrapper around log() to log a batch of training embedding - sets dataset to "training" - ''' + """ return self.log( - embedding_data=embedding_data, - input_uri=input_uri, + embedding_data=embedding_data, + input_uri=input_uri, dataset="training", - category_name=category_name + category_name=category_name, ) - + def log_production(self, embedding_data: list, input_uri: list, category_name: list): - ''' + """ Small wrapper around log() to log a batch of production embedding - sets dataset to "production" - ''' + """ return self.log( - embedding_data=embedding_data, - input_uri=input_uri, + embedding_data=embedding_data, + input_uri=input_uri, dataset="production", - category_name=category_name + category_name=category_name, ) - + def log_triage(self, embedding_data: list, input_uri: list, category_name: list): - ''' + """ Small wrapper around log() to log a batch of triage embedding - sets dataset to "triage" - ''' + """ return self.log( - embedding_data=embedding_data, - input_uri=input_uri, + embedding_data=embedding_data, + input_uri=input_uri, dataset="triage", - category_name=category_name + category_name=category_name, ) - - def get_nearest_neighbors(self, embedding, n_results=10, category_name=None, dataset="training"): - ''' + + def get_nearest_neighbors( + self, embedding, n_results=10, category_name=None, dataset="training" + ): + """ Gets the nearest neighbors of a single embedding - ''' - x = requests.post(self._api_url + "/get_nearest_neighbors", data = json.dumps({ - "embedding": embedding, - "n_results": n_results, - "category_name": category_name, - "dataset": dataset - }) ) + """ + x = requests.post( + self._api_url + "/get_nearest_neighbors", + data=json.dumps( + { + "embedding": embedding, + "n_results": n_results, + "category_name": category_name, + "dataset": dataset, + } + ), + ) if x.status_code == 200: return x.json() else: - return False \ No newline at end of file + return False diff --git a/chroma-client/tests/test_client.py b/chroma-client/tests/test_client.py index 6923060..f1a8322 100644 --- a/chroma-client/tests/test_client.py +++ b/chroma-client/tests/test_client.py @@ -4,11 +4,14 @@ from chroma_client import Chroma import pytest import time from httpx import AsyncClient + # from ..api import app # this wont work because i moved the file + @pytest.fixture def anyio_backend(): - return 'asyncio' + return "asyncio" + def test_init(): chroma = Chroma() @@ -25,4 +28,3 @@ def test_init(): # chroma = Chroma(url="http://test/api/v1") # response = await chroma.count() # raise Exception("response" + response) - diff --git a/chroma-server/chroma_server/algorithms/rand_subsample.py b/chroma-server/chroma_server/algorithms/rand_subsample.py index dbe40a2..4952d28 100644 --- a/chroma-server/chroma_server/algorithms/rand_subsample.py +++ b/chroma-server/chroma_server/algorithms/rand_subsample.py @@ -1,8 +1,8 @@ - import random + def rand_bisectional_subsample(data): """ Randomly bisectionally subsample a list of data to size. """ - return data.sample(frac=0.5, replace=True, random_state=1) \ No newline at end of file + return data.sample(frac=0.5, replace=True, random_state=1) diff --git a/chroma-server/chroma_server/algorithms/stub_distances.py b/chroma-server/chroma_server/algorithms/stub_distances.py index d46221a..60ef41b 100644 --- a/chroma-server/chroma_server/algorithms/stub_distances.py +++ b/chroma-server/chroma_server/algorithms/stub_distances.py @@ -2,22 +2,23 @@ import numpy as np import json import ast + def class_distances(data): - '''' + """' This is all very subject to change, so essentially just copy and paste from what we had before - ''' + """ return False # def unpack_annotations(embeddings): # annotations = [json.loads(embedding['infer'])["annotations"]for embedding in embeddings] - # annotations = [annotation for annotation_list in annotations for annotation in annotation_list] + # annotations = [annotation for annotation_list in annotations for annotation in annotation_list] # # Unpack embedding data # embeddings = [embedding["embedding_data"] for embedding in embeddings] # embedding_vectors_by_category = {} # for embedding_annotation_pair in zip(embeddings, annotations): # data = np.array(embedding_annotation_pair[0]) - # category = embedding_annotation_pair[1]['category_id'] + # category = embedding_annotation_pair[1]['category_id'] # if category in embedding_vectors_by_category.keys(): # embedding_vectors_by_category[category] = np.append( # embedding_vectors_by_category[category], data[np.newaxis, :], axis=0 @@ -84,5 +85,5 @@ def class_distances(data): # if (len(inferences) == 0): # raise Exception("No inferences found for datapoint") - - # return output_distances \ No newline at end of file + + # return output_distances diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index ecf98da..11136da 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -11,7 +11,6 @@ from chroma_server.types import AddEmbedding, QueryEmbedding from chroma_server.utils import logger - # Boot script db = DuckDB ann_index = Hnswlib @@ -34,104 +33,112 @@ if os.path.exists(".chroma/index.bin"): app._ann_index.load(app._db.count(), len(app._db.fetch(limit=1).embedding_data)) - # API Endpoints + @app.get("/api/v1") async def root(): - ''' + """ Heartbeat endpoint - ''' + """ return {"nanosecond heartbeat": int(1000 * time.time_ns())} + @app.post("/api/v1/add", status_code=status.HTTP_201_CREATED) async def add_to_db(new_embedding: AddEmbedding): - ''' + """ Save embedding to database - supports single or batched embeddings - ''' + """ app._db.add_batch( - new_embedding.embedding_data, - new_embedding.input_uri, + new_embedding.embedding_data, + new_embedding.input_uri, new_embedding.dataset, - new_embedding.custom_quality_score, - new_embedding.category_name - ) + new_embedding.custom_quality_score, + new_embedding.category_name, + ) return {"response": "Added record to database"} + @app.get("/api/v1/process") async def process(): - ''' + """ Currently generates an index for the embedding db - ''' + """ app._ann_index.run(app._db.fetch()) + @app.get("/api/v1/fetch") async def fetch(where_filter={}, sort=None, limit=None): - ''' + """ Fetches embeddings from the database - enables filtering by where_filter, sorting by key, and limiting the number of results - ''' + """ return app._db.fetch(where_filter, sort, limit).to_dict(orient="records") + @app.get("/api/v1/count") async def count(): - ''' + """ Returns the number of records in the database - ''' - return ({"count": app._db.count()}) + """ + return {"count": app._db.count()} + @app.get("/api/v1/persist") async def persist(): - ''' + """ Persist the database and index to disk - ''' + """ if not os.path.exists(".chroma"): os.mkdir(".chroma") - + app._db.persist() app._ann_index.persist() return True + @app.get("/api/v1/reset") async def reset(): - ''' + """ Reset the database and index - ''' + """ shutil.rmtree(".chroma", ignore_errors=True) app._db = db() app._ann_index = ann_index() return True + @app.get("/api/v1/rand") async def rand(where_filter={}, sort=None, limit=None): - ''' + """ Randomly bisection the database - ''' + """ results = app._db.fetch(where_filter, sort, limit) rand = rand_bisectional_subsample(results) return rand.to_dict(orient="records") + @app.post("/api/v1/get_nearest_neighbors") async def get_nearest_neighbors(embedding: QueryEmbedding): - ''' + """ return the distance, database ids, and embedding themselves for the input embedding - ''' + """ ids = None filter_by_where = {} if embedding.category_name is not None: - filter_by_where['category_name'] = embedding.category_name + filter_by_where["category_name"] = embedding.category_name if embedding.dataset is not None: - filter_by_where['dataset'] = embedding.dataset + filter_by_where["dataset"] = embedding.dataset if filter_by_where is not None: ids = app._db.fetch(filter_by_where)["id"].tolist() - + nn = app._ann_index.get_nearest_neighbors(embedding.embedding, embedding.n_results, ids) return { "ids": nn[0].tolist()[0], "embeddings": app._db.get_by_ids(nn[0].tolist()[0]).to_dict(orient="records"), - "distances": nn[1].tolist()[0] - } \ No newline at end of file + "distances": nn[1].tolist()[0], + } diff --git a/chroma-server/chroma_server/db/abstract.py b/chroma-server/chroma_server/db/abstract.py index bb30044..60df453 100644 --- a/chroma-server/chroma_server/db/abstract.py +++ b/chroma-server/chroma_server/db/abstract.py @@ -1,6 +1,7 @@ from abc import abstractmethod -class Database(): + +class Database: @abstractmethod def __init__(self): pass @@ -23,4 +24,4 @@ class Database(): @abstractmethod def load(self): - pass \ No newline at end of file + pass diff --git a/chroma-server/chroma_server/db/duckdb.py b/chroma-server/chroma_server/db/duckdb.py index f896bad..317dad2 100644 --- a/chroma-server/chroma_server/db/duckdb.py +++ b/chroma-server/chroma_server/db/duckdb.py @@ -4,12 +4,14 @@ import duckdb import numpy as np import pandas as pd + class DuckDB(Database): _conn = None def __init__(self): self._conn = duckdb.connect() - self._conn.execute(''' + self._conn.execute( + """ CREATE TABLE embeddings ( id integer PRIMARY KEY, embedding_data REAL[], @@ -18,32 +20,39 @@ class DuckDB(Database): custom_quality_score REAL, category_name STRING ) - ''') + """ + ) # ids to manage internal bookkeeping and *nothing else*, users should not have to care about these ids - self._conn.execute(''' + self._conn.execute( + """ CREATE SEQUENCE seq_id START 1; - ''') + """ + ) - self._conn.execute(''' + self._conn.execute( + """ -- change the default null sorting order to either NULLS FIRST and NULLS LAST PRAGMA default_null_order='NULLS LAST'; -- change the default sorting order to either DESC or ASC PRAGMA default_order='DESC'; - ''') + """ + ) return - def add_batch(self, embedding_data, input_uri, dataset=None, custom_quality_score=None, category_name=None): - ''' + def add_batch( + self, embedding_data, input_uri, dataset=None, custom_quality_score=None, category_name=None + ): + """ Add embeddings to the database This accepts both a single input and a list of inputs - ''' + """ # create list of the types of all inputs types = [type(x).__name__ for x in [embedding_data, input_uri]] # if all of the types are 'list' - do batch mode - if all(x == 'list' for x in types): + if all(x == "list" for x in types): lengths = [len(x) for x in [embedding_data, input_uri]] # accepts some inputs as str or none, and this multiples them out to the correct length @@ -57,41 +66,56 @@ class DuckDB(Database): # we have to move from column to row format for duckdb data_to_insert = [] for i in range(lengths[0]): - data_to_insert.append([embedding_data[i], input_uri[i], dataset[i], custom_quality_score[i], category_name[i]]) + data_to_insert.append( + [ + embedding_data[i], + input_uri[i], + dataset[i], + custom_quality_score[i], + category_name[i], + ] + ) if all(x == lengths[0] for x in lengths): - self._conn.executemany(''' - INSERT INTO embeddings VALUES (nextval('seq_id'), ?, ?, ?, ?, ?)''', - data_to_insert + self._conn.executemany( + """ + INSERT INTO embeddings VALUES (nextval('seq_id'), ?, ?, ?, ?, ?)""", + data_to_insert, ) return - + # if any of the types are 'list' - throw an error if any(x == list for x in [input_uri, dataset, custom_quality_score, category_name]): - raise Exception("Invalid input types. One input is a list where others are not: " + str(types)) + raise Exception( + "Invalid input types. One input is a list where others are not: " + str(types) + ) # single insert mode # This should never fire because we do everything in batch mode, but given the mode away from duckdb likely, I am just leaving it in - self._conn.execute(''' - INSERT INTO embeddings VALUES (nextval('seq_id'), ?, ?, ?, ?, ?)''', - [embedding_data, input_uri, dataset, custom_quality_score, category_name] + self._conn.execute( + """ + INSERT INTO embeddings VALUES (nextval('seq_id'), ?, ?, ?, ?, ?)""", + [embedding_data, input_uri, dataset, custom_quality_score, category_name], ) - - def count(self): - return self._conn.execute(''' - SELECT COUNT(*) FROM embeddings; - ''').fetchone()[0] - def update(self, data): # call this update_custom_quality_score! that is all it does - ''' + def count(self): + return self._conn.execute( + """ + SELECT COUNT(*) FROM embeddings; + """ + ).fetchone()[0] + + def update(self, data): # call this update_custom_quality_score! that is all it does + """ I was not able to figure out (yet) how to do a bulk update in duckdb This is going to be fairly slow - ''' - for element in data: - if element['custom_quality_score'] is None: + """ + for element in data: + if element["custom_quality_score"] is None: continue - self._conn.execute(f''' - UPDATE embeddings SET custom_quality_score={element['custom_quality_score']} WHERE id={element['id']}''' + self._conn.execute( + f""" + UPDATE embeddings SET custom_quality_score={element['custom_quality_score']} WHERE id={element['id']}""" ) def fetch(self, where_filter={}, sort=None, limit=None): @@ -99,12 +123,12 @@ class DuckDB(Database): if where_filter is not None: if not isinstance(where_filter, dict): raise Exception("Invalid where_filter: " + str(where_filter)) - + # ensure where_filter is a flat dict for key in where_filter: if isinstance(where_filter[key], dict): raise Exception("Invalid where_filter: " + str(where_filter)) - + where_filter = " AND ".join([f"{key} = '{value}'" for key, value in where_filter.items()]) if where_filter: @@ -116,7 +140,9 @@ class DuckDB(Database): if limit is not None or isinstance(limit, int): where_filter += f" LIMIT {limit}" - return self._conn.execute(f''' + return ( + self._conn.execute( + f""" SELECT id, embedding_data, @@ -127,41 +153,49 @@ class DuckDB(Database): FROM embeddings {where_filter} - ''').fetchdf().replace({np.nan: None}) # replace nan with None for json serialization + """ + ) + .fetchdf() + .replace({np.nan: None}) + ) # replace nan with None for json serialization def delete_batch(self, batch): raise NotImplementedError def persist(self): - ''' + """ Persist the database to disk - ''' + """ if self._conn is None: return - self._conn.execute(''' + self._conn.execute( + """ COPY (SELECT * FROM embeddings) TO '.chroma/chroma.parquet' (FORMAT PARQUET); - ''') + """ + ) def load(self, path=".chroma/chroma.parquet"): - ''' + """ Load the database from disk - ''' + """ self._conn.execute(f"INSERT INTO embeddings SELECT * FROM read_parquet('{path}');") def get_by_ids(self, ids=list): # select from duckdb table where ids are in the list if not isinstance(ids, list): raise Exception("ids must be a list") - + if not ids: # create an empty pandas dataframe return pd.DataFrame() - return self._conn.execute(f''' + return ( + self._conn.execute( + f""" SELECT id, embedding_data, @@ -173,4 +207,8 @@ class DuckDB(Database): embeddings WHERE id IN ({','.join([str(x) for x in ids])}) - ''').fetchdf().replace({np.nan: None}) # replace nan with None for json serialization \ No newline at end of file + """ + ) + .fetchdf() + .replace({np.nan: None}) + ) # replace nan with None for json serialization diff --git a/chroma-server/chroma_server/index/abstract.py b/chroma-server/chroma_server/index/abstract.py index 2b03cc8..86df060 100644 --- a/chroma-server/chroma_server/index/abstract.py +++ b/chroma-server/chroma_server/index/abstract.py @@ -1,6 +1,7 @@ from abc import abstractmethod -class Index(): + +class Index: @abstractmethod def __init__(self): pass @@ -23,4 +24,4 @@ class Index(): @abstractmethod def load(self): - pass \ No newline at end of file + pass diff --git a/chroma-server/chroma_server/index/hnswlib.py b/chroma-server/chroma_server/index/hnswlib.py index 8b36384..9fde81f 100644 --- a/chroma-server/chroma_server/index/hnswlib.py +++ b/chroma-server/chroma_server/index/hnswlib.py @@ -3,6 +3,7 @@ import numpy as np from chroma_server.index.abstract import Index from chroma_server.utils import logger + class Hnswlib(Index): _index = None @@ -14,20 +15,22 @@ class Hnswlib(Index): # more comments available at the source: https://github.com/nmslib/hnswlib # We split the data in two batches: - data1 = embedding_data['embedding_data'].to_numpy().tolist() + data1 = embedding_data["embedding_data"].to_numpy().tolist() dim = len(data1[0]) - num_elements = len(data1) + num_elements = len(data1) # logger.debug("dimensionality is:", dim) # logger.debug("total number of elements is:", num_elements) # logger.debug("max elements", num_elements//2) - concatted_data = data1 + concatted_data = data1 # logger.debug("concatted_data", len(concatted_data)) - - p = hnswlib.Index(space='l2', dim=dim) # # Declaring index, possible options are l2, cosine or ip - p.init_index(max_elements=len(data1), ef_construction=100, M=16) # Initing index + + p = hnswlib.Index( + space="l2", dim=dim + ) # # Declaring index, possible options are l2, cosine or ip + p.init_index(max_elements=len(data1), ef_construction=100, M=16) # Initing index p.set_ef(10) # Controlling the recall by setting ef: - p.set_num_threads(4) # Set number of threads used during batch search/construction + p.set_num_threads(4) # Set number of threads used during batch search/construction # logger.debug("Adding first batch of elements", (len(data1))) p.add_items(data1, embedding_data["id"]) @@ -37,12 +40,15 @@ class Hnswlib(Index): # logger.debug("database_ids", database_ids) # logger.debug("distances", distances) # logger.debug(len(distances)) - logger.debug("Recall for the first batch:" + str(np.mean(database_ids.reshape(-1) == np.arange(len(data1))))) + logger.debug( + "Recall for the first batch:" + + str(np.mean(database_ids.reshape(-1) == np.arange(len(data1)))) + ) self._index = p def fetch(self, query): - raise NotImplementedError + raise NotImplementedError def delete_batch(self, batch): raise NotImplementedError @@ -51,12 +57,12 @@ class Hnswlib(Index): if self._index is None: return self._index.save_index(".chroma/index.bin") - logger.debug('Index saved to .chroma/index.bin') + logger.debug("Index saved to .chroma/index.bin") def load(self, elements, dimensionality): - p = hnswlib.Index(space='l2', dim= dimensionality) + p = hnswlib.Index(space="l2", dim=dimensionality) self._index = p - self._index.load_index(".chroma/index.bin", max_elements= elements) + self._index.load_index(".chroma/index.bin", max_elements=elements) # do knn_query on hnswlib to get nearest neighbors def get_nearest_neighbors(self, query, k, ids=None): diff --git a/chroma-server/chroma_server/test/test_api.py b/chroma-server/chroma_server/test/test_api.py index 8c84fa3..7b1ad9d 100644 --- a/chroma-server/chroma_server/test/test_api.py +++ b/chroma-server/chroma_server/test/test_api.py @@ -4,32 +4,45 @@ from httpx import AsyncClient from ..api import app + @pytest.fixture def anyio_backend(): - return 'asyncio' + return "asyncio" + @pytest.mark.anyio async def test_root(): async with AsyncClient(app=app, base_url="http://test") as ac: response = await ac.get("/api/v1") assert response.status_code == 200 - assert abs(response.json()["nanosecond heartbeat"] - int(1000 * time.time_ns())) < 3_000_000_000 # a billion nanoseconds = 3s + assert ( + abs(response.json()["nanosecond heartbeat"] - int(1000 * time.time_ns())) < 3_000_000_000 + ) # a billion nanoseconds = 3s + async def post_one_record(ac): - return await ac.post("/api/v1/add", json={ - "embedding_data": [1.02, 2.03, 3.03], - "input_uri": "https://example.com", - "dataset": "coco", - "category_name": "person" - }) + return await ac.post( + "/api/v1/add", + json={ + "embedding_data": [1.02, 2.03, 3.03], + "input_uri": "https://example.com", + "dataset": "coco", + "category_name": "person", + }, + ) + async def post_batch_records(ac): - return await ac.post("/api/v1/add", json={ - "embedding_data": [[1.1, 2.3, 3.2], [1.2, 2.24, 3.2]], - "input_uri": ["https://example.com", "https://example.com"], - "dataset": "training", - "category_name": "person" - }) + return await ac.post( + "/api/v1/add", + json={ + "embedding_data": [[1.1, 2.3, 3.2], [1.2, 2.24, 3.2]], + "input_uri": ["https://example.com", "https://example.com"], + "dataset": "training", + "category_name": "person", + }, + ) + @pytest.mark.anyio async def test_add_to_db(): @@ -38,6 +51,7 @@ async def test_add_to_db(): assert response.status_code == 201 assert response.json() == {"response": "Added record to database"} + @pytest.mark.anyio async def test_add_to_db_batch(): async with AsyncClient(app=app, base_url="http://test") as ac: @@ -45,6 +59,7 @@ async def test_add_to_db_batch(): assert response.status_code == 201 assert response.json() == {"response": "Added record to database"} + @pytest.mark.anyio async def test_fetch_from_db(): async with AsyncClient(app=app, base_url="http://test") as ac: @@ -53,15 +68,17 @@ async def test_fetch_from_db(): assert response.status_code == 200 assert len(response.json()) == 1 + @pytest.mark.anyio async def test_count_from_db(): async with AsyncClient(app=app, base_url="http://test") as ac: - await ac.get("/api/v1/reset") # reset db + await ac.get("/api/v1/reset") # reset db await post_batch_records(ac) response = await ac.get("/api/v1/count") assert response.status_code == 200 assert response.json() == {"count": 2} + @pytest.mark.anyio async def test_reset_db(): async with AsyncClient(app=app, base_url="http://test") as ac: @@ -74,25 +91,19 @@ async def test_reset_db(): response = await ac.get("/api/v1/count") assert response.json() == {"count": 0} + @pytest.mark.anyio async def test_get_nearest_neighbors(): async with AsyncClient(app=app, base_url="http://test") as ac: await ac.get("/api/v1/reset") await post_batch_records(ac) await ac.get("/api/v1/process") - response = await ac.post("/api/v1/get_nearest_neighbors", json={"embedding": [1.1, 2.3, 3.2], "n_results": 1}) + response = await ac.post( + "/api/v1/get_nearest_neighbors", json={"embedding": [1.1, 2.3, 3.2], "n_results": 1} + ) assert response.status_code == 200 assert len(response.json()["ids"]) == 1 -@pytest.mark.anyio -async def test_get_nearest_neighbors_filter(): - async with AsyncClient(app=app, base_url="http://test") as ac: - await ac.get("/api/v1/reset") - await post_batch_records(ac) - await ac.get("/api/v1/process") - response = await ac.post("/api/v1/get_nearest_neighbors", json={"embedding": [1.1, 2.3, 3.2], "n_results": 1, "dataset": "training", "category_name": "monkey"}) - assert response.status_code == 200 - assert len(response.json()["ids"]) == 0 @pytest.mark.anyio async def test_get_nearest_neighbors_filter(): @@ -100,7 +111,34 @@ async def test_get_nearest_neighbors_filter(): await ac.get("/api/v1/reset") await post_batch_records(ac) await ac.get("/api/v1/process") - response = await ac.post("/api/v1/get_nearest_neighbors", json={"embedding": [1.1, 2.3, 3.2], "n_results": 2, "dataset": "training", "category_name": "person"}) + response = await ac.post( + "/api/v1/get_nearest_neighbors", + json={ + "embedding": [1.1, 2.3, 3.2], + "n_results": 1, + "dataset": "training", + "category_name": "monkey", + }, + ) + assert response.status_code == 200 + assert len(response.json()["ids"]) == 0 + + +@pytest.mark.anyio +async def test_get_nearest_neighbors_filter(): + async with AsyncClient(app=app, base_url="http://test") as ac: + await ac.get("/api/v1/reset") + await post_batch_records(ac) + await ac.get("/api/v1/process") + response = await ac.post( + "/api/v1/get_nearest_neighbors", + json={ + "embedding": [1.1, 2.3, 3.2], + "n_results": 2, + "dataset": "training", + "category_name": "person", + }, + ) assert response.status_code == 200 assert len(response.json()["ids"]) == 2 @@ -118,4 +156,4 @@ async def test_get_nearest_neighbors_filter(): # Purposefully untested # - process -# - rand \ No newline at end of file +# - rand diff --git a/chroma-server/chroma_server/types/__init__.py b/chroma-server/chroma_server/types/__init__.py index 309c264..8b1ad1b 100644 --- a/chroma-server/chroma_server/types/__init__.py +++ b/chroma-server/chroma_server/types/__init__.py @@ -6,9 +6,10 @@ class AddEmbedding(BaseModel): embedding_data: list input_uri: Union[str, list] dataset: Union[str, list] = None - custom_quality_score: Union[float, list] = None + custom_quality_score: Union[float, list] = None category_name: Union[str, list] = None + class QueryEmbedding(BaseModel): embedding: list n_results: int = 10 diff --git a/chroma-server/chroma_server/utils.py b/chroma-server/chroma_server/utils.py index 9da6b01..1976460 100644 --- a/chroma-server/chroma_server/utils.py +++ b/chroma-server/chroma_server/utils.py @@ -1,5 +1,6 @@ import logging + def setup_logging(): logging.basicConfig(filename="chroma_logs.log") logger = logging.getLogger("Chroma") @@ -7,4 +8,5 @@ def setup_logging(): logger.debug("Logger created") return logger -logger = setup_logging() \ No newline at end of file + +logger = setup_logging() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ac1b975 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,8 @@ +[tool.black] +line-length = 100 + +# Black will refuse to run if it's not this version. +required-version = "22.6.0" + +# Ensure black's output will be compatible with all listed versions. +target-version = ['py36', 'py37', 'py38', 'py39', 'py310'] \ No newline at end of file From e9ab1ddb8824604a39dfb2f5153f1c04128c6426 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 31 Oct 2022 14:28:12 -0700 Subject: [PATCH 02/22] capture anonymized events with posthog --- chroma-server/.env | 2 ++ chroma-server/chroma_server/api.py | 9 +++-- chroma-server/chroma_server/index/hnswlib.py | 2 +- .../chroma_server/{utils.py => logger.py} | 0 chroma-server/chroma_server/utils/__init__.py | 0 .../chroma_server/utils/config/__init__.py | 0 .../chroma_server/utils/config/settings.py | 13 +++++++ .../chroma_server/utils/telemetry/__init__.py | 0 .../chroma_server/utils/telemetry/abstract.py | 10 ++++++ .../chroma_server/utils/telemetry/capture.py | 34 +++++++++++++++++++ chroma-server/requirements.txt | 4 ++- 11 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 chroma-server/.env rename chroma-server/chroma_server/{utils.py => logger.py} (100%) create mode 100644 chroma-server/chroma_server/utils/__init__.py create mode 100644 chroma-server/chroma_server/utils/config/__init__.py create mode 100644 chroma-server/chroma_server/utils/config/settings.py create mode 100644 chroma-server/chroma_server/utils/telemetry/__init__.py create mode 100644 chroma-server/chroma_server/utils/telemetry/abstract.py create mode 100644 chroma-server/chroma_server/utils/telemetry/capture.py diff --git a/chroma-server/.env b/chroma-server/.env new file mode 100644 index 0000000..a321294 --- /dev/null +++ b/chroma-server/.env @@ -0,0 +1,2 @@ +disable_anonymized_telemetry=False +telemetry_anonymized_uuid=d77eeadd-d0c7-4105-af4f-9201bb563217 diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index ecf98da..1a02789 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -8,9 +8,8 @@ from chroma_server.db.duckdb import DuckDB from chroma_server.index.hnswlib import Hnswlib from chroma_server.algorithms.rand_subsample import rand_bisectional_subsample from chroma_server.types import AddEmbedding, QueryEmbedding -from chroma_server.utils import logger - - +from chroma_server.logger import logger +from chroma_server.utils.telemetry.capture import Capture # Boot script db = DuckDB @@ -33,10 +32,10 @@ if os.path.exists(".chroma/index.bin"): logger.info("Loading existing chroma index") app._ann_index.load(app._db.count(), len(app._db.fetch(limit=1).embedding_data)) - +chroma_telemetry = Capture() +chroma_telemetry.capture('server-start') # API Endpoints - @app.get("/api/v1") async def root(): ''' diff --git a/chroma-server/chroma_server/index/hnswlib.py b/chroma-server/chroma_server/index/hnswlib.py index 8b36384..d2f8819 100644 --- a/chroma-server/chroma_server/index/hnswlib.py +++ b/chroma-server/chroma_server/index/hnswlib.py @@ -1,7 +1,7 @@ import hnswlib import numpy as np from chroma_server.index.abstract import Index -from chroma_server.utils import logger +from chroma_server.logger import logger class Hnswlib(Index): diff --git a/chroma-server/chroma_server/utils.py b/chroma-server/chroma_server/logger.py similarity index 100% rename from chroma-server/chroma_server/utils.py rename to chroma-server/chroma_server/logger.py diff --git a/chroma-server/chroma_server/utils/__init__.py b/chroma-server/chroma_server/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chroma-server/chroma_server/utils/config/__init__.py b/chroma-server/chroma_server/utils/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chroma-server/chroma_server/utils/config/settings.py b/chroma-server/chroma_server/utils/config/settings.py new file mode 100644 index 0000000..fb2f377 --- /dev/null +++ b/chroma-server/chroma_server/utils/config/settings.py @@ -0,0 +1,13 @@ +from functools import lru_cache +from pydantic import BaseSettings + +class Settings(BaseSettings): + disable_anonymized_telemetry: bool = False + telemetry_anonymized_uuid: str = 'not-set' + + class Config: + env_file = ".env" + +@lru_cache() +def get_settings(): + return Settings() \ No newline at end of file diff --git a/chroma-server/chroma_server/utils/telemetry/__init__.py b/chroma-server/chroma_server/utils/telemetry/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chroma-server/chroma_server/utils/telemetry/abstract.py b/chroma-server/chroma_server/utils/telemetry/abstract.py new file mode 100644 index 0000000..021340b --- /dev/null +++ b/chroma-server/chroma_server/utils/telemetry/abstract.py @@ -0,0 +1,10 @@ +from abc import abstractmethod + +class Telemetry(): + @abstractmethod + def __init__(self): + pass + + @abstractmethod + def add_batch(self, batch): + pass \ No newline at end of file diff --git a/chroma-server/chroma_server/utils/telemetry/capture.py b/chroma-server/chroma_server/utils/telemetry/capture.py new file mode 100644 index 0000000..4b95391 --- /dev/null +++ b/chroma-server/chroma_server/utils/telemetry/capture.py @@ -0,0 +1,34 @@ +import posthog +import uuid +import sys +from chroma_server.utils.telemetry.abstract import Telemetry +from chroma_server.utils.config.settings import get_settings + +class Capture(Telemetry): + _conn = None + _telemetry_anonymized_uuid = None + + def __init__(self): + if get_settings().disable_anonymized_telemetry: + posthog.disabled = True + + # disable telemetry if we're running tests + if "pytest" in sys.modules: + posthog.disabled = True + + posthog.project_api_key = 'phc_YeUxaojbKk5KPi8hNlx1bBKHzuZ4FDtl67kH1blv8Bh' + posthog.host = 'https://app.posthog.com' + self._conn = posthog + + if get_settings().telemetry_anonymized_uuid == 'not-set': + self._telemetry_anonymized_uuid = uuid.uuid4() + + with open(".env", "a") as f: + f.write(f"\ntelemetry_anonymized_uuid={self._telemetry_anonymized_uuid}\n") + + else: + self._telemetry_anonymized_uuid = get_settings().telemetry_anonymized_uuid + + def capture(self, event, properties=None): + self._conn.capture(self._telemetry_anonymized_uuid, event, properties) + diff --git a/chroma-server/requirements.txt b/chroma-server/requirements.txt index 4cad8d2..e805dc5 100644 --- a/chroma-server/requirements.txt +++ b/chroma-server/requirements.txt @@ -4,4 +4,6 @@ pyarrow==9.0.0 numpy==1.23.4 pandas==1.5.0 duckdb==0.5.1 -hnswlib @ git+https://oauth2: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@github.com/chroma-core/hnswlib.git \ No newline at end of file +hnswlib @ git+https://oauth2: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@github.com/chroma-core/hnswlib.git +posthog +uuid==1.30 \ No newline at end of file From e4413c219c6ef1336b4c43e513b36617bd6ea4b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 31 Oct 2022 14:32:53 -0700 Subject: [PATCH 03/22] fixes --- chroma-server/chroma_server/utils/config/settings.py | 2 +- chroma-server/chroma_server/utils/telemetry/abstract.py | 2 +- chroma-server/chroma_server/utils/telemetry/capture.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chroma-server/chroma_server/utils/config/settings.py b/chroma-server/chroma_server/utils/config/settings.py index fb2f377..a7d0e69 100644 --- a/chroma-server/chroma_server/utils/config/settings.py +++ b/chroma-server/chroma_server/utils/config/settings.py @@ -3,7 +3,7 @@ from pydantic import BaseSettings class Settings(BaseSettings): disable_anonymized_telemetry: bool = False - telemetry_anonymized_uuid: str = 'not-set' + telemetry_anonymized_uuid: str = False class Config: env_file = ".env" diff --git a/chroma-server/chroma_server/utils/telemetry/abstract.py b/chroma-server/chroma_server/utils/telemetry/abstract.py index 021340b..921c399 100644 --- a/chroma-server/chroma_server/utils/telemetry/abstract.py +++ b/chroma-server/chroma_server/utils/telemetry/abstract.py @@ -6,5 +6,5 @@ class Telemetry(): pass @abstractmethod - def add_batch(self, batch): + def capture(self, event, properties=None): pass \ No newline at end of file diff --git a/chroma-server/chroma_server/utils/telemetry/capture.py b/chroma-server/chroma_server/utils/telemetry/capture.py index 4b95391..bb04cf5 100644 --- a/chroma-server/chroma_server/utils/telemetry/capture.py +++ b/chroma-server/chroma_server/utils/telemetry/capture.py @@ -20,7 +20,7 @@ class Capture(Telemetry): posthog.host = 'https://app.posthog.com' self._conn = posthog - if get_settings().telemetry_anonymized_uuid == 'not-set': + if get_settings().telemetry_anonymized_uuid == False: self._telemetry_anonymized_uuid = uuid.uuid4() with open(".env", "a") as f: From 290d8f3a3239198f277c4e746c27cdf668396cc8 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 31 Oct 2022 22:02:48 -0700 Subject: [PATCH 04/22] wip --- chroma-server/chroma_server/api.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 1a02789..6ddf288 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -4,12 +4,34 @@ import time from fastapi import FastAPI, Response, status + from chroma_server.db.duckdb import DuckDB from chroma_server.index.hnswlib import Hnswlib from chroma_server.algorithms.rand_subsample import rand_bisectional_subsample from chroma_server.types import AddEmbedding, QueryEmbedding from chroma_server.logger import logger from chroma_server.utils.telemetry.capture import Capture +from chroma_server.utils.config.settings import get_settings + +import sentry_sdk +from sentry_sdk import configure_scope +from posthog.sentry.posthog_integration import PostHogIntegration + +PostHogIntegration.organization = "chroma" + +sentry_sdk.init( + dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896", + + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + # We recommend adjusting this value in production, + traces_sample_rate=1.0, + integrations=[PostHogIntegration()], +) + +# raise Exception("get_settings().telemetry_anonymized_uuid", get_settings().telemetry_anonymized_uuid) +with configure_scope() as scope: + scope.set_tag('posthog_distinct_id', get_settings().telemetry_anonymized_uuid) # Boot script db = DuckDB @@ -35,6 +57,10 @@ if os.path.exists(".chroma/index.bin"): chroma_telemetry = Capture() chroma_telemetry.capture('server-start') +@app.get("/sentry-debug") +async def trigger_error(): + division_by_zero = 1 / 0 + # API Endpoints @app.get("/api/v1") async def root(): From bd9ffde2b0bde1c5e7a50b33ea57d2b45f790ebf Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 1 Nov 2022 08:35:44 -0700 Subject: [PATCH 05/22] add multi-endpoint sentry tracking --- chroma-server/.env | 1 + chroma-server/chroma_server/api.py | 29 +++++-------------- .../chroma_server/utils/config/settings.py | 3 ++ .../chroma_server/utils/error_reporting.py | 29 +++++++++++++++++++ 4 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 chroma-server/chroma_server/utils/error_reporting.py diff --git a/chroma-server/.env b/chroma-server/.env index a321294..36b637f 100644 --- a/chroma-server/.env +++ b/chroma-server/.env @@ -1,2 +1,3 @@ disable_anonymized_telemetry=False telemetry_anonymized_uuid=d77eeadd-d0c7-4105-af4f-9201bb563217 +environment=development \ No newline at end of file diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 6ddf288..669ab63 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -1,9 +1,13 @@ import os +from random import sample import shutil import time +from typing import Callable from fastapi import FastAPI, Response, status - +from fastapi import Body, FastAPI, HTTPException, Request +from fastapi.exceptions import RequestValidationError +from fastapi.routing import APIRoute from chroma_server.db.duckdb import DuckDB from chroma_server.index.hnswlib import Hnswlib @@ -13,25 +17,9 @@ from chroma_server.logger import logger from chroma_server.utils.telemetry.capture import Capture from chroma_server.utils.config.settings import get_settings -import sentry_sdk -from sentry_sdk import configure_scope -from posthog.sentry.posthog_integration import PostHogIntegration +from chroma_server.utils.error_reporting import init_error_reporting -PostHogIntegration.organization = "chroma" - -sentry_sdk.init( - dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896", - - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for performance monitoring. - # We recommend adjusting this value in production, - traces_sample_rate=1.0, - integrations=[PostHogIntegration()], -) - -# raise Exception("get_settings().telemetry_anonymized_uuid", get_settings().telemetry_anonymized_uuid) -with configure_scope() as scope: - scope.set_tag('posthog_distinct_id', get_settings().telemetry_anonymized_uuid) +init_error_reporting() # Boot script db = DuckDB @@ -57,9 +45,6 @@ if os.path.exists(".chroma/index.bin"): chroma_telemetry = Capture() chroma_telemetry.capture('server-start') -@app.get("/sentry-debug") -async def trigger_error(): - division_by_zero = 1 / 0 # API Endpoints @app.get("/api/v1") diff --git a/chroma-server/chroma_server/utils/config/settings.py b/chroma-server/chroma_server/utils/config/settings.py index a7d0e69..56ac11f 100644 --- a/chroma-server/chroma_server/utils/config/settings.py +++ b/chroma-server/chroma_server/utils/config/settings.py @@ -1,9 +1,12 @@ from functools import lru_cache +from typing import Union from pydantic import BaseSettings class Settings(BaseSettings): disable_anonymized_telemetry: bool = False telemetry_anonymized_uuid: str = False + environment: str = 'development' + user_sentry_dsn: str = '' class Config: env_file = ".env" diff --git a/chroma-server/chroma_server/utils/error_reporting.py b/chroma-server/chroma_server/utils/error_reporting.py new file mode 100644 index 0000000..cfe40f2 --- /dev/null +++ b/chroma-server/chroma_server/utils/error_reporting.py @@ -0,0 +1,29 @@ +from chroma_server.utils.config.settings import get_settings + +import sentry_sdk +from sentry_sdk.client import Client +from sentry_sdk import configure_scope +from posthog.sentry.posthog_integration import PostHogIntegration +PostHogIntegration.organization = "chroma" +sample_rate = 1.0 +if get_settings().environment == "production": + sample_rate = 0.1 + +def init_error_reporting(): + chroma_client = Client(dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896") + if get_settings().user_sentry_dsn: + user_client = Client(dsn=get_settings().user_sentry_dsn) + + def send_event(event): + chroma_client.capture_event(event) + if get_settings().user_sentry_dsn: + user_client.capture_event(event) + + sentry_sdk.init( + transport=send_event, + traces_sample_rate=sample_rate, + integrations=[PostHogIntegration()], + environment=get_settings().environment + ) + with configure_scope() as scope: + scope.set_tag('posthog_distinct_id', get_settings().telemetry_anonymized_uuid) \ No newline at end of file From cf5f4afa63209a845307ed74eb628bc7e56db721 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 1 Nov 2022 08:39:47 -0700 Subject: [PATCH 06/22] dont report errors if the user disables telemetry --- chroma-server/chroma_server/utils/error_reporting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chroma-server/chroma_server/utils/error_reporting.py b/chroma-server/chroma_server/utils/error_reporting.py index cfe40f2..0d2da5b 100644 --- a/chroma-server/chroma_server/utils/error_reporting.py +++ b/chroma-server/chroma_server/utils/error_reporting.py @@ -15,7 +15,8 @@ def init_error_reporting(): user_client = Client(dsn=get_settings().user_sentry_dsn) def send_event(event): - chroma_client.capture_event(event) + if not get_settings().disable_anonymized_telemetry: + chroma_client.capture_event(event) if get_settings().user_sentry_dsn: user_client.capture_event(event) From ea552b88b11b6d166a586611d2781537f1879a63 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 1 Nov 2022 08:42:39 -0700 Subject: [PATCH 07/22] add sentry_sdk to requirements.txt --- chroma-server/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chroma-server/requirements.txt b/chroma-server/requirements.txt index e805dc5..863cf6b 100644 --- a/chroma-server/requirements.txt +++ b/chroma-server/requirements.txt @@ -6,4 +6,5 @@ pandas==1.5.0 duckdb==0.5.1 hnswlib @ git+https://oauth2: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@github.com/chroma-core/hnswlib.git posthog -uuid==1.30 \ No newline at end of file +uuid==1.30 +sentry_sdk \ No newline at end of file From 6b0f48b9fdd74797276ee8eb5658c081e51608c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 1 Nov 2022 12:21:35 -0700 Subject: [PATCH 08/22] this should work but doesnt --- chroma-server/chroma_server/utils/error_reporting.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/chroma-server/chroma_server/utils/error_reporting.py b/chroma-server/chroma_server/utils/error_reporting.py index 0d2da5b..e086947 100644 --- a/chroma-server/chroma_server/utils/error_reporting.py +++ b/chroma-server/chroma_server/utils/error_reporting.py @@ -9,8 +9,15 @@ sample_rate = 1.0 if get_settings().environment == "production": sample_rate = 0.1 +def strip_sensitive_data(event, hint): + if 'server_name' in event: + del event['server_name'] + return event + def init_error_reporting(): - chroma_client = Client(dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896") + chroma_client = Client( + dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896", + ) if get_settings().user_sentry_dsn: user_client = Client(dsn=get_settings().user_sentry_dsn) @@ -24,7 +31,8 @@ def init_error_reporting(): transport=send_event, traces_sample_rate=sample_rate, integrations=[PostHogIntegration()], - environment=get_settings().environment + environment=get_settings().environment, + before_send=strip_sensitive_data, ) with configure_scope() as scope: scope.set_tag('posthog_distinct_id', get_settings().telemetry_anonymized_uuid) \ No newline at end of file From 14d7791fb54b5babc01939c6ffed95e5c6d5a59f Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 1 Nov 2022 17:38:47 -0700 Subject: [PATCH 09/22] remove user defined sentry --- chroma-server/.env | 4 ++-- chroma-server/chroma_server/api.py | 4 ++-- .../chroma_server/utils/config/settings.py | 3 +-- .../chroma_server/utils/error_reporting.py | 13 +------------ .../chroma_server/utils/telemetry/capture.py | 2 +- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/chroma-server/.env b/chroma-server/.env index 36b637f..a75cfd9 100644 --- a/chroma-server/.env +++ b/chroma-server/.env @@ -1,3 +1,3 @@ disable_anonymized_telemetry=False -telemetry_anonymized_uuid=d77eeadd-d0c7-4105-af4f-9201bb563217 -environment=development \ No newline at end of file +environment=development +telemetry_anonymized_uuid=f80b11fc-1c5a-4a90-ba35-8c3a3c5371cc diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 669ab63..9c8abdf 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -15,10 +15,10 @@ from chroma_server.algorithms.rand_subsample import rand_bisectional_subsample from chroma_server.types import AddEmbedding, QueryEmbedding from chroma_server.logger import logger from chroma_server.utils.telemetry.capture import Capture -from chroma_server.utils.config.settings import get_settings - from chroma_server.utils.error_reporting import init_error_reporting +chroma_telemetry = Capture() +chroma_telemetry.capture('server-start') init_error_reporting() # Boot script diff --git a/chroma-server/chroma_server/utils/config/settings.py b/chroma-server/chroma_server/utils/config/settings.py index 56ac11f..e04d0dc 100644 --- a/chroma-server/chroma_server/utils/config/settings.py +++ b/chroma-server/chroma_server/utils/config/settings.py @@ -4,9 +4,8 @@ from pydantic import BaseSettings class Settings(BaseSettings): disable_anonymized_telemetry: bool = False - telemetry_anonymized_uuid: str = False + telemetry_anonymized_uuid: str = '' environment: str = 'development' - user_sentry_dsn: str = '' class Config: env_file = ".env" diff --git a/chroma-server/chroma_server/utils/error_reporting.py b/chroma-server/chroma_server/utils/error_reporting.py index e086947..283d4aa 100644 --- a/chroma-server/chroma_server/utils/error_reporting.py +++ b/chroma-server/chroma_server/utils/error_reporting.py @@ -15,20 +15,9 @@ def strip_sensitive_data(event, hint): return event def init_error_reporting(): - chroma_client = Client( - dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896", - ) - if get_settings().user_sentry_dsn: - user_client = Client(dsn=get_settings().user_sentry_dsn) - - def send_event(event): - if not get_settings().disable_anonymized_telemetry: - chroma_client.capture_event(event) - if get_settings().user_sentry_dsn: - user_client.capture_event(event) sentry_sdk.init( - transport=send_event, + dsn="https://ef5fae1e461f49b3a7a2adf3404378ab@o4504080408051712.ingest.sentry.io/4504080409296896", traces_sample_rate=sample_rate, integrations=[PostHogIntegration()], environment=get_settings().environment, diff --git a/chroma-server/chroma_server/utils/telemetry/capture.py b/chroma-server/chroma_server/utils/telemetry/capture.py index bb04cf5..70b5935 100644 --- a/chroma-server/chroma_server/utils/telemetry/capture.py +++ b/chroma-server/chroma_server/utils/telemetry/capture.py @@ -20,7 +20,7 @@ class Capture(Telemetry): posthog.host = 'https://app.posthog.com' self._conn = posthog - if get_settings().telemetry_anonymized_uuid == False: + if not get_settings().telemetry_anonymized_uuid: self._telemetry_anonymized_uuid = uuid.uuid4() with open(".env", "a") as f: From 676c9826f161470ff162f1b7f989fca29caff569 Mon Sep 17 00:00:00 2001 From: Luke VanderHart Date: Fri, 4 Nov 2022 09:22:47 -0400 Subject: [PATCH 10/22] ADR for Clickhouse architecture --- .gitignore | 1 + doc/adr/2022-11-03-clickhouse-architecture.md | 61 ++++++++++++++++++ .../diagram.graffle | Bin 0 -> 147555 bytes .../diagram.png | Bin 0 -> 38499 bytes 4 files changed, 62 insertions(+) create mode 100644 .gitignore create mode 100644 doc/adr/2022-11-03-clickhouse-architecture.md create mode 100644 doc/adr/2022-11-03-clickhouse-architecture/diagram.graffle create mode 100644 doc/adr/2022-11-03-clickhouse-architecture/diagram.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/doc/adr/2022-11-03-clickhouse-architecture.md b/doc/adr/2022-11-03-clickhouse-architecture.md new file mode 100644 index 0000000..7aebe54 --- /dev/null +++ b/doc/adr/2022-11-03-clickhouse-architecture.md @@ -0,0 +1,61 @@ +# Clickhouse Architecture + +## Context + +The current prototype of Chroma Server uses DuckDB and Parquet files for +persistence. Although the simplicity and batch data retrieval +characteristics of this are attractive, we determine that this is +suboptimal for three primary reasons: + +- Chroma's primary mode of ingesting data is a stream of small batches + of embeddings. DuckDB and Parquet are not well optimized for + streaming input. In fact, it's impossible to append to a Parquet + file; the entire file must be re-written or additional files + created. +- DuckDB explicitly does not support multiple writer processes, which + we will likely want in the medium term. +- DuckDB + Parquet requires an explicit flush or write operation to + persist data. This adds an element of "state management" and is + complexity that we would rather not expose to the client. + +Therefore, we are looking for an architecture with the following quantities: + +- Efficient streaming ingest +- Efficient bulk read to pull data into memory for processing (OLAP) +- Low volume transactional CRUD operations (e.g datasets and metadata) +- Low administrative overhead, to present as small a client API as + possible. We want to avoid exposing any methods aside from those + that define Chroma as a product, for a focused user experience. + +## Decision + +We will use Clickhouse as the persistence layer. For now it will be +the only persistence mechanism used by Chroma. + +Instances of Chroma Server will be stateless, aside from caching for +performance. + +The MVP will run in a simple `docker-compose` configuration with a +single Clickhouse and a single Chroma Server. + +The Chroma Server will, when required to service a read operation, +pull entire datasets from Clickhouse into memory and keep them cached +in order to perform algorithmic work on demand. + +![Clickhouse Architecture](./2022-11-01-clickhouse-architecture/diagram.png "Clickhouse Architecture") + +## Consequences + +- The MVP is actually less complex than the previous DuckDB based + solution. +- We can scale horizontally by adding more Chroma Server instances in + a cluster. +- We can scale vertically by using a larger instance of Clickhouse or + moving to clustered Clickhouse as workloads grow. +- At some point in the future, we will likely need to add an OLTP + database, when the system contains enough transactional data that + Clickhouse starts to perform poorly for row-based updates. +- We maintain separation of concerns, and can make future changes to + the data persistence mechanisms without disrupting the backend + protocol between Chroma Client and Chroma Server, or the user-facing + API. diff --git a/doc/adr/2022-11-03-clickhouse-architecture/diagram.graffle b/doc/adr/2022-11-03-clickhouse-architecture/diagram.graffle new file mode 100644 index 0000000000000000000000000000000000000000..dab2c015e27e0e6eb69f6fc1d7b74bedf574abc5 GIT binary patch literal 147555 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

HS7;@dV^qA52?-Dup>0I(u|9 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 z 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 literal 0 HcmV?d00001 diff --git a/doc/adr/2022-11-03-clickhouse-architecture/diagram.png b/doc/adr/2022-11-03-clickhouse-architecture/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..ed6761242844abe15ab65b77871f927882287901 GIT binary patch literal 38499 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 Date: Mon, 7 Nov 2022 15:53:06 -0800 Subject: [PATCH 11/22] shell files for packaging and setup --- bin/setup_linux.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 bin/setup_linux.sh diff --git a/bin/setup_linux.sh b/bin/setup_linux.sh new file mode 100644 index 0000000..ecfbfdb --- /dev/null +++ b/bin/setup_linux.sh @@ -0,0 +1,40 @@ +# install pip +apt install python3-pip + +# install docker +sudo apt-get update +sudo apt-get install \ + ca-certificates \ + curl \ + gnupg \ + lsb-release + +sudo mkdir -p /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg + +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +sudo apt-get update + +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin + +pip3 install docker-compose + + +# get the code +git clone https://oauth2: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@github.com/chroma-core/chroma.git + +#checkout the right branch +cd chroma +git checkout jeff/clickhouse + +# run docker +cd chroma-server +docker-compose up -d --build + +# install chroma-client +cd ../chroma-client +pip3 install --upgrade pip # you have to do this or it will use UNKNOWN as the package name +pip3 install . \ No newline at end of file From e61b79392baabd3cadaa6d8e045553a3de06c623 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 7 Nov 2022 16:01:45 -0800 Subject: [PATCH 12/22] default scope and small test script --- bin/test.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 bin/test.py diff --git a/bin/test.py b/bin/test.py new file mode 100644 index 0000000..31e31b6 --- /dev/null +++ b/bin/test.py @@ -0,0 +1,23 @@ +from chroma_client import Chroma + +chroma = Chroma() +chroma.set_space_key('sample_space') +print("Getting heartbeat to verify the server is up") +print(chroma.heartbeat()) + +print("Logging embeddings into the database") +chroma.log( + [[1,2,3,4,5], [5,4,3,2,1], [10,9,8,7,6]], + ["/images/1", "/images/2", "/images/3"], + ["training", "training", "training"], + ['spoon', 'knife', 'fork'] +) + +# print("fetch", chroma.fetch()) +print("Generating the index") +print(chroma.process()) + +print("Running a nearest neighbor search") +print(chroma.get_nearest_neighbors([1,2,3,4,5], 1)) + +print("Success! Everything worked!") \ No newline at end of file From edc6a8c1f4c0ccd9ba68315c0f5027533423c77c Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 7 Nov 2022 16:02:22 -0800 Subject: [PATCH 13/22] actually add default scope, change pull branch to this one --- bin/setup_linux.sh | 2 +- chroma-client/src/chroma_client/client.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/setup_linux.sh b/bin/setup_linux.sh index ecfbfdb..e462488 100644 --- a/bin/setup_linux.sh +++ b/bin/setup_linux.sh @@ -28,7 +28,7 @@ git clone https://oauth2:github_pat_11AAGZWEA0i4gAuiLWSPPV_j72DZ4YurWwGV6wm0RHBy #checkout the right branch cd chroma -git checkout jeff/clickhouse +git checkout jeff/packaging # run docker cd chroma-server diff --git a/chroma-client/src/chroma_client/client.py b/chroma-client/src/chroma_client/client.py index 95fd2ba..307a1df 100644 --- a/chroma-client/src/chroma_client/client.py +++ b/chroma-client/src/chroma_client/client.py @@ -5,7 +5,7 @@ from typing import Union class Chroma: _api_url = "http://localhost:8000/api/v1" - _space_key = None + _space_key = "default_scope" def __init__(self, url=None, app=None, model_version=None, layer=None): """Initialize Chroma client""" From 8be6b24c29b2c3ab089d40cf96d1a3ac206df5ac Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 7 Nov 2022 16:34:22 -0800 Subject: [PATCH 14/22] simple setup scripts --- README.md | 21 +++++++++++++++++++++ bin/setup_linux.sh | 8 +++++--- bin/setup_mac.sh | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 bin/setup_mac.sh diff --git a/README.md b/README.md index f095d14..81ea2fb 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,24 @@ Contents: - `/chroma-client` - Python client for Chroma - `/chroma-server` - FastAPI server used as the backend for Chroma client + + +### Get up and running on Linux +No requirements +``` +/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/jeffchuber/effcbac05021e863bbd634f4b7d0283d/raw/4d38b150809d6ccbc379f88433cadd86c81d32cd/chroma_setup.sh)" +python3 chroma/bin/test.py +``` + +### Get up and running on Mac +Requirements +- git +- Docker & `docker-compose` +- pip + +``` +/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/jeffchuber/27a3cbb28e6521c811da6398346cd35f/raw/55c2d82870436431120a9446b47f19b72d88fa31/chroma_setup_mac.sh)" +python3 chroma/bin/test.py +``` + +* These urls will be swapped out for the link in the repo once it is live \ No newline at end of file diff --git a/bin/setup_linux.sh b/bin/setup_linux.sh index e462488..63b42e7 100644 --- a/bin/setup_linux.sh +++ b/bin/setup_linux.sh @@ -1,9 +1,11 @@ +#!/usr/bin/env bash + # install pip -apt install python3-pip +apt install -y python3-pip # install docker sudo apt-get update -sudo apt-get install \ +sudo apt-get -y install \ ca-certificates \ curl \ gnupg \ @@ -18,7 +20,7 @@ echo \ sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin +sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin pip3 install docker-compose diff --git a/bin/setup_mac.sh b/bin/setup_mac.sh new file mode 100644 index 0000000..5c7b1bf --- /dev/null +++ b/bin/setup_mac.sh @@ -0,0 +1,19 @@ +# requirements +# - docker +# - pip + +# get the code +git clone https://oauth2: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@github.com/chroma-core/chroma.git + +#checkout the right branch +cd chroma +git checkout jeff/packaging + +# run docker +cd chroma-server +docker-compose up -d --build + +# install chroma-client +cd ../chroma-client +pip install --upgrade pip # you have to do this or it will use UNKNOWN as the package name +pip install . \ No newline at end of file From 52a277f935430878b1ae2e77ad84e26fb122d989 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Mon, 7 Nov 2022 16:35:17 -0800 Subject: [PATCH 15/22] show expected output --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 81ea2fb..151f39c 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,18 @@ Requirements python3 chroma/bin/test.py ``` -* These urls will be swapped out for the link in the repo once it is live \ No newline at end of file +* These urls will be swapped out for the link in the repo once it is live + + +### You should see something like + +``` +Getting heartbeat to verify the server is up +{'nanosecond heartbeat': 1667865642509760965000} +Logging embeddings into the database +Generating the index +True +Running a nearest neighbor search +{'ids': ['11540ca6-ebbc-4c81-8299-108d8c47c88c'], 'embeddings': [['sample_space', '11540ca6-ebbc-4c81-8299-108d8c47c88c', [1.0, 2.0, 3.0, 4.0, 5.0], '/images/1', 'training', None, 'spoon']], 'distances': [0.0]} +Success! Everything worked! +``` \ No newline at end of file From 4383f40829984368d4242a7aabf3dfd1bed0e95d Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 8 Nov 2022 11:28:58 -0800 Subject: [PATCH 16/22] remove dupe, add pydantic and pin versions --- chroma-server/chroma_server/api.py | 3 --- chroma-server/requirements.txt | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 9c8abdf..df6a170 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -42,9 +42,6 @@ if os.path.exists(".chroma/index.bin"): logger.info("Loading existing chroma index") app._ann_index.load(app._db.count(), len(app._db.fetch(limit=1).embedding_data)) -chroma_telemetry = Capture() -chroma_telemetry.capture('server-start') - # API Endpoints @app.get("/api/v1") diff --git a/chroma-server/requirements.txt b/chroma-server/requirements.txt index 863cf6b..9ca9947 100644 --- a/chroma-server/requirements.txt +++ b/chroma-server/requirements.txt @@ -7,4 +7,5 @@ duckdb==0.5.1 hnswlib @ git+https://oauth2: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@github.com/chroma-core/hnswlib.git posthog uuid==1.30 -sentry_sdk \ No newline at end of file +sentry_sdk=1.10.1 +pydantic=1.9.0 \ No newline at end of file From 5b2b2dd4ef3c5b8d5bb7bab3b7837c14e9db72c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 8 Nov 2022 11:32:24 -0800 Subject: [PATCH 17/22] remove ununsed imports --- chroma-server/chroma_server/api.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 47b73de..549ab77 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -1,13 +1,8 @@ import os -from random import sample import shutil import time -from typing import Callable -from fastapi import FastAPI, Response, status -from fastapi import Body, FastAPI, HTTPException, Request -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute +from fastapi import FastAPI, status from chroma_server.db.duckdb import DuckDB from chroma_server.index.hnswlib import Hnswlib From 7a4f185b5905222e0addec0b5c4c82cfbd665268 Mon Sep 17 00:00:00 2001 From: Jeffrey Huber Date: Tue, 8 Nov 2022 11:42:56 -0800 Subject: [PATCH 18/22] cleanup --- chroma-server/chroma_server/api.py | 2 +- chroma-server/chroma_server/db/clickhouse.py | 3 +-- chroma-server/chroma_server/db/duckdb.py | 2 -- chroma-server/chroma_server/index/hnswlib.py | 5 ----- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/chroma-server/chroma_server/api.py b/chroma-server/chroma_server/api.py index 7312a9a..d3b2db9 100644 --- a/chroma-server/chroma_server/api.py +++ b/chroma-server/chroma_server/api.py @@ -133,6 +133,6 @@ async def get_nearest_neighbors(embedding: QueryEmbedding): uuids, distances = app._ann_index.get_nearest_neighbors(embedding.embedding, embedding.n_results, ids) return { "ids": uuids, - "embeddings": app._db.get_by_ids(uuids),# + "embeddings": app._db.get_by_ids(uuids), "distances": distances.tolist()[0] } \ No newline at end of file diff --git a/chroma-server/chroma_server/db/clickhouse.py b/chroma-server/chroma_server/db/clickhouse.py index 41882a6..4fbe205 100644 --- a/chroma-server/chroma_server/db/clickhouse.py +++ b/chroma-server/chroma_server/db/clickhouse.py @@ -19,7 +19,6 @@ class Clickhouse(Database): ) ENGINE = Memory''') def __init__(self): - # https://stackoverflow.com/questions/59224272/connect-cannot-assign-requested-address client = Client('clickhouse') self._conn = client self._create_table_embeddings() @@ -36,7 +35,7 @@ class Clickhouse(Database): def count(self): return self._conn.execute('SELECT COUNT() FROM embeddings') - def update(self, data): # call this update_custom_quality_score! that is all it does + def update(self, data): pass def fetch(self, where_filter={}, sort=None, limit=None): diff --git a/chroma-server/chroma_server/db/duckdb.py b/chroma-server/chroma_server/db/duckdb.py index a4c8fe0..de68071 100644 --- a/chroma-server/chroma_server/db/duckdb.py +++ b/chroma-server/chroma_server/db/duckdb.py @@ -1,8 +1,6 @@ from os import EX_CANTCREAT from chroma_server.db.abstract import Database import duckdb -# import numpy as np -# import pandas as pd class DuckDB(Database): _conn = None diff --git a/chroma-server/chroma_server/index/hnswlib.py b/chroma-server/chroma_server/index/hnswlib.py index 86d022d..f488f10 100644 --- a/chroma-server/chroma_server/index/hnswlib.py +++ b/chroma-server/chroma_server/index/hnswlib.py @@ -8,11 +8,6 @@ class Hnswlib(Index): _index = None - # these data structures enable us to map between uuids and ids - # - our uuids are strings (clickhouse doesnt do autoincrementing ids for performance) - # - but hnswlib uses integers only as ids - # - so this is a temporary bandaid. - # TODO: this should get written to disk somehow or we the index will be come useless after a restart _id_to_uuid = {} _uuid_to_id = {} From 5cd1f272a19d148a7d69873df678c2c42d16f6a6 Mon Sep 17 00:00:00 2001 From: Luke VanderHart Date: Wed, 9 Nov 2022 15:44:46 -0500 Subject: [PATCH 19/22] run server tests in docker-compose cluster --- .github/workflows/chroma-release.yml | 1 + .github/workflows/chroma-server-test.yml | 13 ++---------- chroma-server/Dockerfile | 12 ++++++++++- chroma-server/README.md | 5 +++-- chroma-server/bin/build | 2 +- chroma-server/bin/test | 9 ++++++++ chroma-server/docker-compose.test.yml | 26 ++++++++++++++++++++++++ chroma-server/requirements_dev.txt | 5 ----- docker-compose.yml | 1 + 9 files changed, 54 insertions(+), 20 deletions(-) create mode 100755 chroma-server/bin/test create mode 100644 chroma-server/docker-compose.test.yml diff --git a/.github/workflows/chroma-release.yml b/.github/workflows/chroma-release.yml index 51ab387..c3f88dc 100644 --- a/.github/workflows/chroma-release.yml +++ b/.github/workflows/chroma-release.yml @@ -44,6 +44,7 @@ jobs: with: context: chroma-server push: true + target: chroma_server tags: ${{ steps.tag.outputs.tag_name}} - name: Get Release Version id: version diff --git a/.github/workflows/chroma-server-test.yml b/.github/workflows/chroma-server-test.yml index 4c60b4b..c2c105d 100644 --- a/.github/workflows/chroma-server-test.yml +++ b/.github/workflows/chroma-server-test.yml @@ -17,19 +17,10 @@ jobs: strategy: matrix: python: ['3.10'] - platform: [ubuntu-latest, macos-latest] + platform: [ubuntu-latest] runs-on: ${{ matrix.platform }} steps: - name: Checkout uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - name: Install test dependencies - run: | - cd chroma-server && python -m pip install -r requirements.txt -r requirements_dev.txt - - name: Install chroma_client - run: cd chroma-client && pip install . - name: Test - run: cd chroma-server && python -m pytest + run: bin/test diff --git a/chroma-server/Dockerfile b/chroma-server/Dockerfile index 4080ad9..a0a65dd 100644 --- a/chroma-server/Dockerfile +++ b/chroma-server/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 python:3.10 +FROM --platform=linux/amd64 python:3.10 AS chroma_server #RUN apt-get update -qq #RUN apt-get install python3.10 python3-pip -y --no-install-recommends && rm -rf /var/lib/apt/lists_/* @@ -15,3 +15,13 @@ EXPOSE 8000 CMD ["uvicorn", "chroma_server:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers"] +# Use a multi-stage build to layer in test dependencies without bloating server image +# https://docs.docker.com/build/building/multi-stage/ +# Note: requires passing --target to docker-build. +FROM chroma_server AS chroma_server_test + +COPY ./requirements_dev.txt requirements_dev.txt +RUN pip install --no-cache-dir --upgrade -r requirements_dev.txt + +CMD ["python", "-m", "pytest"] + diff --git a/chroma-server/README.md b/chroma-server/README.md index 972e683..cabe66b 100644 --- a/chroma-server/README.md +++ b/chroma-server/README.md @@ -12,7 +12,8 @@ pip install -r requirements.txt pip install -r requirements_dev.txt ``` -To run tests, run `pytest`. +To run tests, run `bin/test`. This will run the test suite inside a +docker compose cluster, with the database available, and clean up when complete. To run the server locally, in development mode, run `uvicorn chroma_server:app --reload` @@ -43,4 +44,4 @@ To run use `docker images` to see what containers and tags you have available: docker run -p 8000:8000 ghcr.io/chroma-core/chroma-server:> ``` -This will expose the internal app at `localhost:8000` \ No newline at end of file +This will expose the internal app at `localhost:8000` diff --git a/chroma-server/bin/build b/chroma-server/bin/build index 2165ba3..5e32419 100755 --- a/chroma-server/bin/build +++ b/chroma-server/bin/build @@ -1,3 +1,3 @@ #!/usr/bin/env bash -docker build . -t ghcr.io/chroma-core/chroma-server:`bin/version` +docker build . --target chroma_server -t ghcr.io/chroma-core/chroma-server:`bin/version` diff --git a/chroma-server/bin/test b/chroma-server/bin/test new file mode 100755 index 0000000..fffaf77 --- /dev/null +++ b/chroma-server/bin/test @@ -0,0 +1,9 @@ +#!/usr/bin/env bash -e + +function cleanup { + docker-compose -f docker-compose.test.yml down +} + +trap cleanup EXIT + +docker-compose -f docker-compose.test.yml run --rm server_test echo hi diff --git a/chroma-server/docker-compose.test.yml b/chroma-server/docker-compose.test.yml new file mode 100644 index 0000000..cb636a2 --- /dev/null +++ b/chroma-server/docker-compose.test.yml @@ -0,0 +1,26 @@ +version: '3.9' + +networks: + my-network: + driver: bridge + +services: + server_test: + build: + context: . + dockerfile: Dockerfile + target: chroma_server_test + depends_on: + - clickhouse + networks: + - my-network + + clickhouse: + image: docker.io/bitnami/clickhouse:22.9 + environment: + - ALLOW_EMPTY_PASSWORD=yes + ports: + - '8123:8123' + - '9000:9000' + networks: + - my-network diff --git a/chroma-server/requirements_dev.txt b/chroma-server/requirements_dev.txt index aced43a..be3caac 100644 --- a/chroma-server/requirements_dev.txt +++ b/chroma-server/requirements_dev.txt @@ -1,8 +1,3 @@ httpx pytest setuptools_scm -duckdb -hnswlib @ git+https://oauth2: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@github.com/chroma-core/hnswlib.git -pandas -numpy -pyarrow \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 06ebee5..536281f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: build: context: ./chroma-server dockerfile: Dockerfile + target: chroma_server volumes: - ./chroma-server/:/chroma-server/ command: uvicorn chroma_server:app --reload --workers 1 --host 0.0.0.0 --port 8000 From 3e7fb137577d9d17f5d896f5bf1a59a73ef0cb6e Mon Sep 17 00:00:00 2001 From: Luke VanderHart Date: Thu, 10 Nov 2022 13:07:07 -0500 Subject: [PATCH 20/22] Use correct path for test script --- .github/workflows/chroma-server-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chroma-server-test.yml b/.github/workflows/chroma-server-test.yml index c2c105d..21a16bf 100644 --- a/.github/workflows/chroma-server-test.yml +++ b/.github/workflows/chroma-server-test.yml @@ -23,4 +23,4 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Test - run: bin/test + run: cd chroma-server && bin/test From a0a57503c48cd3d05f1234fbf0180fb95780fba7 Mon Sep 17 00:00:00 2001 From: Luke VanderHart Date: Thu, 10 Nov 2022 13:09:28 -0500 Subject: [PATCH 21/22] Update test script to work on Linux as well as OSX --- chroma-server/bin/test | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chroma-server/bin/test b/chroma-server/bin/test index fffaf77..d47a468 100755 --- a/chroma-server/bin/test +++ b/chroma-server/bin/test @@ -1,4 +1,6 @@ -#!/usr/bin/env bash -e +#!/usr/bin/env bash + +set -e function cleanup { docker-compose -f docker-compose.test.yml down From 593a0797b6c0fce8284b55eb250b88f872d788f3 Mon Sep 17 00:00:00 2001 From: Luke VanderHart Date: Thu, 10 Nov 2022 13:11:53 -0500 Subject: [PATCH 22/22] Actually run tests --- chroma-server/bin/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chroma-server/bin/test b/chroma-server/bin/test index d47a468..793da14 100755 --- a/chroma-server/bin/test +++ b/chroma-server/bin/test @@ -8,4 +8,4 @@ function cleanup { trap cleanup EXIT -docker-compose -f docker-compose.test.yml run --rm server_test echo hi +docker-compose -f docker-compose.test.yml run --rm server_test