Skip to content

Commit

Permalink
Merge pull request #53 from PinataCloud/feat/vectors
Browse files Browse the repository at this point in the history
feat/vectors
  • Loading branch information
stevedylandev authored Nov 29, 2024
2 parents cfe26e4 + 3e7c876 commit 70eabb5
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 4 deletions.
72 changes: 72 additions & 0 deletions src/core/files/deleteFileVectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { PinataConfig, VectorizeFileResponse } from "../types";
import {
PinataError,
NetworkError,
AuthenticationError,
ValidationError,
} from "../../utils/custom-errors";

export const deleteFileVectors = async (
config: PinataConfig | undefined,
fileId: string,
): Promise<VectorizeFileResponse> => {
if (!config) {
throw new ValidationError("Pinata configuration is missing");
}

let headers: Record<string, string>;

if (config.customHeaders && Object.keys(config.customHeaders).length > 0) {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
...config.customHeaders,
};
} else {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
Source: "sdk/vectorizeFile",
};
}

let endpoint: string = "https://uploads.pinata.cloud/v3";

if (config.endpointUrl) {
endpoint = config.endpointUrl;
}

try {
const request = await fetch(`${endpoint}/vectorize/files/${fileId}`, {
method: "DELETE",
headers: headers,
});

if (!request.ok) {
const errorData = await request.text();
if (request.status === 401 || request.status === 403) {
throw new AuthenticationError(
`Authentication failed: ${errorData}`,
request.status,
errorData,
);
}
throw new NetworkError(
`HTTP error: ${errorData}`,
request.status,
errorData,
);
}

const res: VectorizeFileResponse = await request.json();
return res;
} catch (error) {
if (error instanceof PinataError) {
throw error;
}
if (error instanceof Error) {
throw new PinataError(
`Error processing vectorize file: ${error.message}`,
);
}
throw new PinataError("An unknown error occurred while vectorizing file");
}
};
72 changes: 72 additions & 0 deletions src/core/files/vectorizeFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { PinataConfig, VectorizeFileResponse } from "../types";
import {
PinataError,
NetworkError,
AuthenticationError,
ValidationError,
} from "../../utils/custom-errors";

export const vectorizeFile = async (
config: PinataConfig | undefined,
fileId: string,
): Promise<VectorizeFileResponse> => {
if (!config) {
throw new ValidationError("Pinata configuration is missing");
}

let headers: Record<string, string>;

if (config.customHeaders && Object.keys(config.customHeaders).length > 0) {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
...config.customHeaders,
};
} else {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
Source: "sdk/vectorizeFile",
};
}

let endpoint: string = "https://uploads.pinata.cloud/v3";

if (config.endpointUrl) {
endpoint = config.endpointUrl;
}

try {
const request = await fetch(`${endpoint}/vectorize/files/${fileId}`, {
method: "POST",
headers: headers,
});

if (!request.ok) {
const errorData = await request.text();
if (request.status === 401 || request.status === 403) {
throw new AuthenticationError(
`Authentication failed: ${errorData}`,
request.status,
errorData,
);
}
throw new NetworkError(
`HTTP error: ${errorData}`,
request.status,
errorData,
);
}

const res: VectorizeFileResponse = await request.json();
return res;
} catch (error) {
if (error instanceof PinataError) {
throw error;
}
if (error instanceof Error) {
throw new PinataError(
`Error processing vectorize file: ${error.message}`,
);
}
throw new PinataError("An unknown error occurred while vectorizing file");
}
};
84 changes: 84 additions & 0 deletions src/core/files/vectorizeQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import type {
PinataConfig,
VectorizeQuery,
VectorizeQueryResponse,
} from "../types";
import {
PinataError,
NetworkError,
AuthenticationError,
ValidationError,
} from "../../utils/custom-errors";

export const vectorizeQuery = async (
config: PinataConfig | undefined,
options: VectorizeQuery,
): Promise<VectorizeQueryResponse> => {
if (!config) {
throw new ValidationError("Pinata configuration is missing");
}

let headers: Record<string, string>;

if (config.customHeaders && Object.keys(config.customHeaders).length > 0) {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
...config.customHeaders,
};
} else {
headers = {
Authorization: `Bearer ${config.pinataJwt}`,
Source: "sdk/vectorQuery",
};
}

let endpoint: string = "https://uploads.pinata.cloud/v3";

if (config.endpointUrl) {
endpoint = config.endpointUrl;
}

const body = JSON.stringify({
text: options.query,
});

try {
const request = await fetch(
`${endpoint}/vectorize/groups/${options.groupId}/query`,
{
method: "POST",
headers: headers,
body: body,
},
);

if (!request.ok) {
const errorData = await request.text();
if (request.status === 401 || request.status === 403) {
throw new AuthenticationError(
`Authentication failed: ${errorData}`,
request.status,
errorData,
);
}
throw new NetworkError(
`HTTP error: ${errorData}`,
request.status,
errorData,
);
}
const res = await request.json();
const resData: VectorizeQueryResponse = res.data;
return resData;
} catch (error) {
if (error instanceof PinataError) {
throw error;
}
if (error instanceof Error) {
throw new PinataError(
`Error processing vectorize file: ${error.message}`,
);
}
throw new PinataError("An unknown error occurred while vectorizing file");
}
};
30 changes: 27 additions & 3 deletions src/core/pinataSDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import type {
FileListResponse,
UpdateGroupFilesResponse,
TopAnalyticsResponse,
VectorizeFileResponse,
VectorizeQuery,
VectorizeQueryResponse,
} from "./types";
import { testAuthentication } from "./authentication/testAuthentication";
import { uploadFile } from "./uploads/file";
Expand Down Expand Up @@ -72,6 +75,9 @@ import { swapHistory } from "./files/swapHistory";
import { deleteSwap } from "./files/deleteSwap";
import { containsCID } from "../utils/gateway-tools";
import { createSignedURL } from "./gateway/createSignedURL";
import { vectorizeFile } from "./files/vectorizeFile";
import { vectorizeQuery } from "./files/vectorizeQuery";
import { deleteFileVectors } from "./files/deleteFileVectors";

const formatConfig = (config: PinataConfig | undefined) => {
let gateway = config?.pinataGateway;
Expand Down Expand Up @@ -180,6 +186,18 @@ class Files {
deleteSwap(cid: string): Promise<string> {
return deleteSwap(this.config, cid);
}

vectorize(fileId: string): Promise<VectorizeFileResponse> {
return vectorizeFile(this.config, fileId);
}

queryVector(options: VectorizeQuery): Promise<VectorizeQueryResponse> {
return vectorizeQuery(this.config, options);
}

deleteVectors(fileId: string): Promise<VectorizeFileResponse> {
return deleteFileVectors(this.config, fileId);
}
}

class UploadBuilder<T> {
Expand All @@ -192,6 +210,7 @@ class UploadBuilder<T> {
private metadata: PinataMetadata | undefined;
private keys: string | undefined;
private groupId: string | undefined;
private vector: boolean | undefined;

constructor(
config: PinataConfig | undefined,
Expand All @@ -216,6 +235,11 @@ class UploadBuilder<T> {
return this;
}

vectorize(): UploadBuilder<T> {
this.vector = true;
return this;
}

// cidVersion(v: 0 | 1): UploadBuilder<T> {
// this.version = v;
// return this;
Expand Down Expand Up @@ -246,6 +270,9 @@ class UploadBuilder<T> {
if (this.groupId) {
options.groupId = this.groupId;
}
if (this.vector) {
options.vectorize = this.vector;
}
this.args[this.args.length - 1] = options;
return this.uploadFunction(this.config, ...this.args).then(
onfulfilled,
Expand Down Expand Up @@ -426,7 +453,6 @@ class Gateways {
createSignedURL(options: SignedUrlOptions): OptimizeImageCreateSignedURL {
return new OptimizeImageCreateSignedURL(this.config, options);
}

}

class OptimizeImageGetCid {
Expand Down Expand Up @@ -752,7 +778,6 @@ class Analytics {
this.bandwidth.updateConfig(newConfig);
}


summary(options: {
domain: string;
start: string;
Expand Down Expand Up @@ -1018,7 +1043,6 @@ class AnalyticsBuilder<T extends AnalyticsQuery, R> {
}
}


class TimeIntervalAnalyticsBuilder extends AnalyticsBuilder<
TimeIntervalAnalyticsQuery,
TimeIntervalAnalyticsResponse
Expand Down
24 changes: 23 additions & 1 deletion src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export type UploadResponse = {
mime_type: string;
user_id: string;
group_id: string | null;
is_duplicate: true | null;
vectorized: true | null;
};

export type FileObject = {
Expand Down Expand Up @@ -49,7 +51,7 @@ export type UploadOptions = {
//pinType?: "async" | "sync" | "cidOnly";
keys?: string;
groupId?: string;
//cidVersion?: 0 | 1;
vectorize?: boolean;
};

export type DeleteResponse = {
Expand Down Expand Up @@ -380,3 +382,23 @@ export type ContainsCIDResponse = {
containsCid: boolean;
cid: string | null;
};

export type VectorizeFileResponse = {
status: boolean;
};

export type VectorizeQuery = {
groupId: string;
query: string;
};

export type VectorQueryMatch = {
file_id: string;
cid: string;
score: number;
};

export type VectorizeQueryResponse = {
count: number;
matches: VectorQueryMatch[];
};
22 changes: 22 additions & 0 deletions src/core/uploads/base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ export const uploadBase64 = async (

const res = await request.json();
const resData: UploadResponse = res.data;
if (options?.vectorize) {
const vectorReq = await fetch(
`${endpoint}/vectorize/files/${resData.id}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`,
},
},
);
if (vectorReq.ok) {
resData.vectorized = true;
return resData;
} else {
const errorData = await vectorReq.text();
throw new NetworkError(
`HTTP error during vectorization: ${errorData}`,
vectorReq.status,
errorData,
);
}
}
return resData;
} catch (error) {
if (error instanceof PinataError) {
Expand Down
Loading

0 comments on commit 70eabb5

Please sign in to comment.