diff --git a/bun.lockb b/bun.lockb index 70ad316..66979cd 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 529d20a..01f5228 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,6 @@ "vitest": "latest" }, "dependencies": { - "@upstash/vector": "^1.0.7" + "@upstash/vector": "^1.1.3" } } diff --git a/readme.md b/readme.md index ae09365..fa4a71e 100644 --- a/readme.md +++ b/readme.md @@ -2,10 +2,9 @@ > [!NOTE] > **This project is in the Experimental Stage.** -> +> > We declare this project experimental to set clear expectations for your usage. There could be known or unknown bugs, the API could evolve, or the project could be discontinued if it does not find community adoption. While we cannot provide professional support for experimental projects, we’d be happy to hear from you if you see value in this project! - Semantic Cache is a tool for caching natural text based on semantic similarity. It's ideal for any task that involves querying or retrieving information based on meaning, such as natural language classification or caching AI responses. Two pieces of text can be similar but not identical (e.g., "great places to check out in Spain" vs. "best places to visit in Spain"). Traditional caching doesn't recognize this semantic similarity and misses opportunities for reuse. Semantic Cache allows you to: @@ -87,6 +86,23 @@ runDemo(); The `minProximity` parameter ranges from `0` to `1`. It lets you define the minimum relevance score to determine a cache hit. The higher this number, the more similar your user input must be to the cached content to be a hit. In practice, a score of 0.95 indicates a very high similarity, while a score of 0.75 already indicates a low similarity. For example, a value of 1.00, the highest possible, would only accept an _exact_ match of your user query and cache content as a cache hit. +### Namespace Support + +You can seperate your data into partitions with namespaces. + +```typescript +import { SemanticCache } from "@upstash/semantic-cache"; +import { Index } from "@upstash/vector"; + +// 👇 your vector database +const index = new Index(); + +// 👇 your semantic cache +const semanticCache = new SemanticCache({ index, minProximity: 0.95, namespace: "user1" }); + +await semanticCache.set("Capital of Turkey", "Ankara"); +``` + ## Examples The following examples demonstrate how you can utilize Semantic Cache in various use cases: diff --git a/src/semantic-cache.test.ts b/src/semantic-cache.test.ts index e3ec434..3b6968c 100644 --- a/src/semantic-cache.test.ts +++ b/src/semantic-cache.test.ts @@ -80,4 +80,35 @@ describe("semantic-cache", () => { expect(firstResult).toBeUndefined(); }); + + test("should work with namespaces", async () => { + const cache1 = new SemanticCache({ + index: new Index(), + minProximity: PROXIMITY_THRESHOLD, + namespace: "cache1", + }); + + const cache2 = new SemanticCache({ + index: new Index(), + minProximity: PROXIMITY_THRESHOLD, + namespace: "cache2", + }); + + const cachedValue1 = "water"; + const cachedValue2 = "H2O"; + + await cache1.set("best drink on a hot day", cachedValue1); + await cache2.set("chemical formula for water", cachedValue2); + await sleep(DELAY_MS); + + const result1 = await cache1.get("what to drink when it's hot"); + const result2 = await cache2.get("what is water's chemical formula"); + + expect(result1).toBe(cachedValue1); + expect(result2).toBe(cachedValue2); + + // Cleanup + await cache1.flush(); + await cache2.flush(); + }); }); diff --git a/src/semantic-cache.ts b/src/semantic-cache.ts index dde332a..62397b8 100644 --- a/src/semantic-cache.ts +++ b/src/semantic-cache.ts @@ -11,15 +11,27 @@ type SemanticCacheConfig = { * Upstash serverless vector client */ index: Index; + + /** + * Optional namespace for the cache + */ + namespace?: string; }; export class SemanticCache { private minProximity: number; private index: Index; + private namespace?: string; constructor(config: SemanticCacheConfig) { this.minProximity = config.minProximity; - this.index = config.index; + + if (config.namespace) { + this.index = config.index.namespace(config.namespace) as unknown as Index; + this.namespace = config.namespace; + } else { + this.index = config.index; + } } async get(key: string): Promise; @@ -86,6 +98,11 @@ export class SemanticCache { } async flush(): Promise { + if (this.namespace) { + await this.index.reset({ namespace: this.namespace }); + return; + } + await this.index.reset(); } }