Skip to content

Commit

Permalink
Merge pull request #996 from andrew-bierman/feat/cf-vectorize-initial
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-bierman authored Jul 20, 2024
2 parents 218effa + 8979c62 commit 8482153
Show file tree
Hide file tree
Showing 47 changed files with 1,059 additions and 31 deletions.
1 change: 1 addition & 0 deletions packages/shared-types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# shared-types
20 changes: 20 additions & 0 deletions packages/shared-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@packrat/shared-types",
"version": "0.0.1",
"source": "src/index.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "NODE_OPTIONS=--max_old_space_size=4096 tsc",
"build:and:install": "yarn build && yarn",
"postinstall": "yarn build",
"clean": "rm -rf dist && rm -rf node_modules"
},
"keywords": [],
"license": "ISC",
"devDependencies": {
"typescript": "^5.5.3"
}
}
1 change: 1 addition & 0 deletions packages/shared-types/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './packAndItemVisibilityFilter';
5 changes: 5 additions & 0 deletions packages/shared-types/src/packAndItemVisibilityFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum PackAndItemVisibilityFilter {
PUBLIC = 'PUBLIC',
PRIVATE = 'PRIVATE',
ALL = 'ALL',
}
22 changes: 22 additions & 0 deletions packages/shared-types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["es6", "DOM"],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"moduleResolution": "node",
"preserveWatchOutput": true,
"skipLibCheck": true,
"allowJs": true,
"strict": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"sourceMap": true,
"declarationMap": true
},
"exclude": ["node_modules"],
"include": ["src"]
}
1 change: 1 addition & 0 deletions packages/validations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@packrat/shared-types": "*",
"@types/express": "^4.17.17",
"@types/node": "^20.14.2",
"express": "^4.19.2",
Expand Down
9 changes: 9 additions & 0 deletions packages/validations/src/validations/itemRoutesValidator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PackAndItemVisibilityFilter } from '@packrat/shared-types';
import { z } from 'zod';

export const getItemByName = z.object({
Expand Down Expand Up @@ -67,3 +68,11 @@ export const getItemsGlobally = z.object({
limit: z.number(),
page: z.number(),
});

export const getSimilarItems = z.object({
id: z.string(),
limit: z.number(),
visibility: z
.nativeEnum(PackAndItemVisibilityFilter)
.default(PackAndItemVisibilityFilter.ALL),
});
9 changes: 9 additions & 0 deletions packages/validations/src/validations/packRoutesValidator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from 'zod';
import { PackAndItemVisibilityFilter } from '@packrat/shared-types';

export const getPacks = z.object({
ownerId: z.string(),
Expand Down Expand Up @@ -43,3 +44,11 @@ export const duplicatePublicPack = z.object({
ownerId: z.string(),
items: z.array(z.string()),
});

export const getSimilarPacks = z.object({
id: z.string(),
limit: z.number(),
visibility: z
.nativeEnum(PackAndItemVisibilityFilter)
.default(PackAndItemVisibilityFilter.ALL),
});
3 changes: 3 additions & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@
"author": "Andrew Bierman",
"license": "ISC",
"dependencies": {
"@cloudflare/ai": "^1.2.2",
"@elysiajs/trpc": "^0.7.0",
"@hono/node-server": "^1.11.0",
"@hono/trpc-server": "^0.1.1",
"@instructor-ai/instructor": "^1.3.0",
"@libsql/client": "^0.4.0-pre.5",
"@packrat/shared-types": "*",
"@packrat/validations": "*",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.7.0",
Expand Down Expand Up @@ -93,6 +95,7 @@
"nodemon": "^3.0.1",
"openai": "4.25.0",
"osmtogeojson": "^3.0.0-beta.5",
"p-queue": "^8.0.1",
"passport": "^0.6.0",
"passport-google-oauth20": "^2.0.0",
"passport-local": "^1.0.0",
Expand Down
1 change: 1 addition & 0 deletions server/src/controllers/item/addItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function addItemRoute() {
packId,
type,
ownerId,
opts.ctx.executionCtx,
);
return result;
});
Expand Down
1 change: 1 addition & 0 deletions server/src/controllers/item/addItemGlobal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function addItemGlobalRoute() {
unit,
type,
ownerId,
opts.ctx.executionCtx,
);
return item;
});
Expand Down
2 changes: 1 addition & 1 deletion server/src/controllers/item/deleteGlobalItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ export function deleteGlobalItemRoute() {
)
.mutation(async (opts) => {
const { itemId } = opts.input;
return await deleteGlobalItemService(itemId);
return await deleteGlobalItemService(itemId, opts.ctx.executionCtx);
});
}
2 changes: 1 addition & 1 deletion server/src/controllers/item/deleteItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export function deleteItemRoute() {
.input(validator.deleteItem)
.mutation(async (opts) => {
const { itemId, packId } = opts.input;
return await deleteItemService(itemId, packId);
return await deleteItemService(itemId, opts.ctx.executionCtx, packId);
});
}
1 change: 1 addition & 0 deletions server/src/controllers/item/editGlobalItemAsDuplicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function editGlobalItemAsDuplicateRoute() {
quantity,
unit,
type,
opts.ctx.executionCtx,
);
return item;
});
Expand Down
10 changes: 9 additions & 1 deletion server/src/controllers/item/editItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ export function editItemRoute() {
throw new Error('Invalid item type');
}

const item = await editItemService(id, name, weight, unit, quantity, type);
const item = await editItemService(
opts.ctx.executionCtx,
id,
name,
weight,
unit,
quantity,
type,
);
return item;
});
}
18 changes: 18 additions & 0 deletions server/src/controllers/item/getSimilarItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getSimilarItemsService } from '../../services/item/getSimilarItemsService';
import { protectedProcedure } from '../../trpc';
import * as validator from '@packrat/validations';

export function getSimilarItemsRoute() {
return protectedProcedure
.input(validator.getSimilarItems)
.query(async (opts) => {
const { id, limit, visibility } = opts.input;

if (limit < 1) {
throw new Error('limit must be greater than 0');
}

const items = await getSimilarItemsService(id, limit, visibility);
return items;
});
}
1 change: 1 addition & 0 deletions server/src/controllers/item/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './getItemById';
export * from './editGlobalItemAsDuplicate';
export * from './getItemsGlobally';
export * from './searchItemsByName';
export * from './getSimilarItems';
7 changes: 6 additions & 1 deletion server/src/controllers/pack/addPack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ export const addPack = async (c) => {
export function addPackRoute() {
return protectedProcedure.input(validator.addPack).mutation(async (opts) => {
const { name, owner_id, is_public } = opts.input;
const pack = await addPackService(name, owner_id, is_public);
const pack = await addPackService(
name,
owner_id,
is_public,
opts.ctx.executionCtx,
);
return pack;
});
}
2 changes: 1 addition & 1 deletion server/src/controllers/pack/deletePack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function deletePackRoute() {
.input(validator.deletePack)
.mutation(async (opts) => {
const { packId } = opts.input;
await deletePackService(packId);
await deletePackService(packId, opts.ctx.executionCtx);
return { msg: 'pack was deleted successfully' };
});
}
7 changes: 6 additions & 1 deletion server/src/controllers/pack/duplicatePublicPack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ export function duplicatePublicPackRoute() {
.input(validator.duplicatePublicPack)
.mutation(async (opts) => {
const { packId, ownerId, items } = opts.input;
const result = await duplicatePublicPackService(packId, ownerId, items);
const result = await duplicatePublicPackService(
packId,
ownerId,
items,
opts.ctx.executionCtx,
);
return result;
});
}
2 changes: 1 addition & 1 deletion server/src/controllers/pack/editPack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const editPack = async (c) => {
export function editPackRoute() {
return protectedProcedure.input(validator.editPack).mutation(async (opts) => {
const packData = opts.input;
const pack = await editPackService(packData);
const pack = await editPackService(packData, opts.ctx.executionCtx);
return pack;
});
}
16 changes: 16 additions & 0 deletions server/src/controllers/pack/getSimilarPacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { protectedProcedure } from '../../trpc';
import { getSimilarPacksService } from '../../services/pack/pack.service';
import { getSimilarPacks } from '@packrat/validations';

export function getSimilarPacksRoute() {
return protectedProcedure.input(getSimilarPacks).query(async (opts) => {
const { id, limit, visibility } = opts.input;

if (limit < 1) {
throw new Error('limit must be greater than 0');
}

const packs = await getSimilarPacksService(id, limit, visibility);
return packs;
});
}
1 change: 1 addition & 0 deletions server/src/controllers/pack/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './duplicatePublicPack';
export * from './getPackById';
export * from './getPublicPacks';
export * from './scorePack';
export * from './getSimilarPacks';
5 changes: 5 additions & 0 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@ import { securityHeaders } from './middleware/securityHeaders';
import { enforceHttps } from './middleware/enforceHttps';
import router from './routes';
import { CORS_METHODS } from './config';
import { Ai } from '@cloudflare/ai';
import { httpDBContext } from './trpc/httpDBContext';

interface Bindings {
[key: string]: any;
DB: IDBDatabase;
VECTOR_INDEX: VectorizeIndex;
AI: Ai;
JWT_VERIFICATION_KEY: string;
APP_URL: string;
CORS_ORIGIN: string;
MAPBOX_ACCESS_TOKEN: string;
CLOUDFLARE_ACCOUNT_ID: string;
VECTORIZE_API_KEY: string;
}

const TRPC_API_ENDPOINT = '/api/trpc';
Expand Down
79 changes: 79 additions & 0 deletions server/src/integrations/ai/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Ai } from "@cloudflare/ai";

class AiClient {
private static _instance: AiClient | null = null;
private apiKey: string;
private accountId: string;
private readonly MODEL_NAME: string = '@cf/baai/bge-base-en-v1.5';
private readonly EXECUTE_AI_MODEL_URL: string;

private constructor(apiKey: string, accountId: string) {
this.apiKey = apiKey;
this.accountId = accountId;
this.EXECUTE_AI_MODEL_URL = `https://api.cloudflare.com/client/v4/accounts/${this.accountId}/ai/run/${this.MODEL_NAME}`;
}

public static get instance(): AiClient {
if (!AiClient._instance) {
throw new Error('AiClient instance not initialized.');
}
return AiClient._instance;
}

public static async init({
apiKey,
accountId,
}: {
apiKey: string;
accountId: string;
}): Promise<void> {
if (!AiClient._instance) {
AiClient._instance = new AiClient(apiKey, accountId);
}
}

public async run(text: string) {
const response = await fetch(this.EXECUTE_AI_MODEL_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify({ text }),
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(
`Failed to get embedding: ${response.statusText} - ${errorText}`,
);
}

return await response.json();
}

public static async getEmbedding(content: string): Promise<number[]> {
const {
result: { data },
} = await AiClient.instance.run(content);
return data[0];
}

// Commented out using AI client and temporalily use REST API instead
// public static async init(cfAi): Promise<void> {
// if (!AiClient._instance) {
// AiClient._instance = new Ai(cfAi);
// }
// }

// public static async getEmbedding(content: string): Promise<number[]> {
// const { data } = await AiClient.instance.run('@cf/baai/bge-base-en-v1.5', { text: [content] });
// return data[0];
// }
}

export { AiClient };

export interface Env {
AI: any;
}
25 changes: 25 additions & 0 deletions server/src/queue/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import PQueue from 'p-queue';

interface QueueTask<T> {
(): Promise<T>;
}

export class Queue {
private static instance: Queue;
private queue: PQueue;

private constructor(concurrency: number = 1) {
this.queue = new PQueue({ concurrency });
}

static getInstance(concurrency: number = 1): Queue {
if (!Queue.instance) {
Queue.instance = new Queue(concurrency);
}
return Queue.instance;
}

async addTask<T>(task: QueueTask<T>): Promise<T> {
return this.queue.add(task);
}
}
Loading

0 comments on commit 8482153

Please sign in to comment.