Skip to content

Commit fca7dbe

Browse files
authored
Add modelInfo, spaceInfo, datasetInfo (#946)
Helpful for #945
1 parent 22e6d4d commit fca7dbe

File tree

11 files changed

+260
-13
lines changed

11 files changed

+260
-13
lines changed

packages/hub/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ For some of the calls, you need to create an account and generate an [access tok
3030
Learn how to find free models using the hub package in this [interactive tutorial](https://scrimba.com/scrim/c7BbVPcd?pl=pkVnrP7uP).
3131

3232
```ts
33-
import { createRepo, uploadFiles, uploadFilesWithProgress, deleteFile, deleteRepo, listFiles, whoAmI } from "@huggingface/hub";
33+
import { createRepo, uploadFiles, uploadFilesWithProgress, deleteFile, deleteRepo, listFiles, whoAmI, modelInfo, listModels } from "@huggingface/hub";
3434
import type { RepoDesignation } from "@huggingface/hub";
3535

3636
const repo: RepoDesignation = { type: "model", name: "myname/some-model" };
@@ -41,6 +41,8 @@ for await (const model of listModels({search: {owner: username}, accessToken: "h
4141
console.log("My model:", model);
4242
}
4343

44+
const specificModel = await modelInfo({name: "openai-community/gpt2"});
45+
4446
await createRepo({ repo, accessToken: "hf_...", license: "mit" });
4547

4648
await uploadFiles({
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { describe, expect, it } from "vitest";
2+
import { datasetInfo } from "./dataset-info";
3+
4+
describe("datasetInfo", () => {
5+
it("should return the dataset info", async () => {
6+
const info = await datasetInfo({
7+
name: "nyu-mll/glue",
8+
});
9+
expect(info).toEqual({
10+
id: "621ffdd236468d709f181e3f",
11+
downloads: expect.any(Number),
12+
gated: false,
13+
name: "nyu-mll/glue",
14+
updatedAt: expect.any(Date),
15+
likes: expect.any(Number),
16+
private: false,
17+
});
18+
});
19+
});

packages/hub/src/lib/dataset-info.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { HUB_URL } from "../consts";
2+
import { createApiError } from "../error";
3+
import type { ApiDatasetInfo } from "../types/api/api-dataset";
4+
import type { CredentialsParams } from "../types/public";
5+
import { checkCredentials } from "../utils/checkCredentials";
6+
import { pick } from "../utils/pick";
7+
import { type DATASET_EXPANDABLE_KEYS, DATASET_EXPAND_KEYS, type DatasetEntry } from "./list-datasets";
8+
9+
export async function datasetInfo<
10+
const T extends Exclude<(typeof DATASET_EXPANDABLE_KEYS)[number], (typeof DATASET_EXPAND_KEYS)[number]> = never,
11+
>(
12+
params: {
13+
name: string;
14+
hubUrl?: string;
15+
additionalFields?: T[];
16+
/**
17+
* Set to limit the number of models returned.
18+
*/
19+
limit?: number;
20+
/**
21+
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
22+
*/
23+
fetch?: typeof fetch;
24+
} & Partial<CredentialsParams>
25+
): Promise<DatasetEntry & Pick<ApiDatasetInfo, T>> {
26+
const accessToken = params && checkCredentials(params);
27+
28+
const search = new URLSearchParams([
29+
...DATASET_EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
30+
...(params?.additionalFields?.map((val) => ["expand", val] satisfies [string, string]) ?? []),
31+
]).toString();
32+
33+
const response = await (params.fetch || fetch)(
34+
`${params?.hubUrl || HUB_URL}/api/datasets/${params.name}?${search.toString()}`,
35+
{
36+
headers: {
37+
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
38+
Accepts: "application/json",
39+
},
40+
}
41+
);
42+
43+
if (!response.ok) {
44+
createApiError(response);
45+
}
46+
47+
const data = await response.json();
48+
49+
return {
50+
...(params?.additionalFields && pick(data, params.additionalFields)),
51+
id: data._id,
52+
name: data.id,
53+
private: data.private,
54+
downloads: data.downloads,
55+
likes: data.likes,
56+
gated: data.gated,
57+
updatedAt: new Date(data.lastModified),
58+
} as DatasetEntry & Pick<ApiDatasetInfo, T>;
59+
}

packages/hub/src/lib/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from "./cache-management";
22
export * from "./commit";
33
export * from "./count-commits";
44
export * from "./create-repo";
5+
export * from "./dataset-info";
56
export * from "./delete-file";
67
export * from "./delete-files";
78
export * from "./delete-repo";
@@ -13,9 +14,11 @@ export * from "./list-datasets";
1314
export * from "./list-files";
1415
export * from "./list-models";
1516
export * from "./list-spaces";
17+
export * from "./model-info";
1618
export * from "./oauth-handle-redirect";
1719
export * from "./oauth-login-url";
1820
export * from "./parse-safetensors-metadata";
21+
export * from "./space-info";
1922
export * from "./upload-file";
2023
export * from "./upload-files";
2124
export * from "./upload-files-with-progress";

packages/hub/src/lib/list-datasets.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import { checkCredentials } from "../utils/checkCredentials";
66
import { parseLinkHeader } from "../utils/parseLinkHeader";
77
import { pick } from "../utils/pick";
88

9-
const EXPAND_KEYS = [
9+
export const DATASET_EXPAND_KEYS = [
1010
"private",
1111
"downloads",
1212
"gated",
1313
"likes",
1414
"lastModified",
1515
] as const satisfies readonly (keyof ApiDatasetInfo)[];
1616

17-
const EXPANDABLE_KEYS = [
17+
export const DATASET_EXPANDABLE_KEYS = [
1818
"author",
1919
"cardData",
2020
"citation",
@@ -45,7 +45,7 @@ export interface DatasetEntry {
4545
}
4646

4747
export async function* listDatasets<
48-
const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never,
48+
const T extends Exclude<(typeof DATASET_EXPANDABLE_KEYS)[number], (typeof DATASET_EXPAND_KEYS)[number]> = never,
4949
>(
5050
params?: {
5151
search?: {
@@ -77,7 +77,7 @@ export async function* listDatasets<
7777
...(params?.search?.query ? { search: params.search.query } : undefined),
7878
}),
7979
...(params?.search?.tags?.map((tag) => ["filter", tag]) ?? []),
80-
...EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
80+
...DATASET_EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
8181
...(params?.additionalFields?.map((val) => ["expand", val] satisfies [string, string]) ?? []),
8282
]).toString();
8383
let url: string | undefined = `${params?.hubUrl || HUB_URL}/api/datasets` + (search ? "?" + search : "");

packages/hub/src/lib/list-models.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { checkCredentials } from "../utils/checkCredentials";
66
import { parseLinkHeader } from "../utils/parseLinkHeader";
77
import { pick } from "../utils/pick";
88

9-
const EXPAND_KEYS = [
9+
export const MODEL_EXPAND_KEYS = [
1010
"pipeline_tag",
1111
"private",
1212
"gated",
@@ -15,7 +15,7 @@ const EXPAND_KEYS = [
1515
"lastModified",
1616
] as const satisfies readonly (keyof ApiModelInfo)[];
1717

18-
const EXPANDABLE_KEYS = [
18+
export const MODEL_EXPANDABLE_KEYS = [
1919
"author",
2020
"cardData",
2121
"config",
@@ -51,7 +51,7 @@ export interface ModelEntry {
5151
}
5252

5353
export async function* listModels<
54-
const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never,
54+
const T extends Exclude<(typeof MODEL_EXPANDABLE_KEYS)[number], (typeof MODEL_EXPAND_KEYS)[number]> = never,
5555
>(
5656
params?: {
5757
search?: {
@@ -85,7 +85,7 @@ export async function* listModels<
8585
...(params?.search?.query ? { search: params.search.query } : undefined),
8686
}),
8787
...(params?.search?.tags?.map((tag) => ["filter", tag]) ?? []),
88-
...EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
88+
...MODEL_EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
8989
...(params?.additionalFields?.map((val) => ["expand", val] satisfies [string, string]) ?? []),
9090
]).toString();
9191
let url: string | undefined = `${params?.hubUrl || HUB_URL}/api/models?${search}`;

packages/hub/src/lib/list-spaces.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ import { checkCredentials } from "../utils/checkCredentials";
66
import { parseLinkHeader } from "../utils/parseLinkHeader";
77
import { pick } from "../utils/pick";
88

9-
const EXPAND_KEYS = ["sdk", "likes", "private", "lastModified"] as const satisfies readonly (keyof ApiSpaceInfo)[];
10-
const EXPANDABLE_KEYS = [
9+
export const SPACE_EXPAND_KEYS = [
10+
"sdk",
11+
"likes",
12+
"private",
13+
"lastModified",
14+
] as const satisfies readonly (keyof ApiSpaceInfo)[];
15+
export const SPACE_EXPANDABLE_KEYS = [
1116
"author",
1217
"cardData",
1318
"datasets",
@@ -37,7 +42,7 @@ export interface SpaceEntry {
3742
}
3843

3944
export async function* listSpaces<
40-
const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never,
45+
const T extends Exclude<(typeof SPACE_EXPANDABLE_KEYS)[number], (typeof SPACE_EXPAND_KEYS)[number]> = never,
4146
>(
4247
params?: {
4348
search?: {
@@ -67,7 +72,9 @@ export async function* listSpaces<
6772
...(params?.search?.query ? { search: params.search.query } : undefined),
6873
}),
6974
...(params?.search?.tags?.map((tag) => ["filter", tag]) ?? []),
70-
...[...EXPAND_KEYS, ...(params?.additionalFields ?? [])].map((val) => ["expand", val] satisfies [string, string]),
75+
...[...SPACE_EXPAND_KEYS, ...(params?.additionalFields ?? [])].map(
76+
(val) => ["expand", val] satisfies [string, string]
77+
),
7178
]).toString();
7279
let url: string | undefined = `${params?.hubUrl || HUB_URL}/api/spaces?${search}`;
7380

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { describe, expect, it } from "vitest";
2+
import { modelInfo } from "./model-info";
3+
4+
describe("modelInfo", () => {
5+
it("should return the model info", async () => {
6+
const info = await modelInfo({
7+
name: "openai-community/gpt2",
8+
});
9+
expect(info).toEqual({
10+
id: "621ffdc036468d709f17434d",
11+
downloads: expect.any(Number),
12+
gated: false,
13+
name: "openai-community/gpt2",
14+
updatedAt: expect.any(Date),
15+
likes: expect.any(Number),
16+
task: "text-generation",
17+
private: false,
18+
});
19+
});
20+
});

packages/hub/src/lib/model-info.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { HUB_URL } from "../consts";
2+
import { createApiError } from "../error";
3+
import type { ApiModelInfo } from "../types/api/api-model";
4+
import type { CredentialsParams } from "../types/public";
5+
import { checkCredentials } from "../utils/checkCredentials";
6+
import { pick } from "../utils/pick";
7+
import { MODEL_EXPAND_KEYS, type MODEL_EXPANDABLE_KEYS, type ModelEntry } from "./list-models";
8+
9+
export async function modelInfo<
10+
const T extends Exclude<(typeof MODEL_EXPANDABLE_KEYS)[number], (typeof MODEL_EXPANDABLE_KEYS)[number]> = never,
11+
>(
12+
params: {
13+
name: string;
14+
hubUrl?: string;
15+
additionalFields?: T[];
16+
/**
17+
* Set to limit the number of models returned.
18+
*/
19+
limit?: number;
20+
/**
21+
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
22+
*/
23+
fetch?: typeof fetch;
24+
} & Partial<CredentialsParams>
25+
): Promise<ModelEntry & Pick<ApiModelInfo, T>> {
26+
const accessToken = params && checkCredentials(params);
27+
28+
const search = new URLSearchParams([
29+
...MODEL_EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
30+
...(params?.additionalFields?.map((val) => ["expand", val] satisfies [string, string]) ?? []),
31+
]).toString();
32+
33+
const response = await (params.fetch || fetch)(
34+
`${params?.hubUrl || HUB_URL}/api/models/${params.name}?${search.toString()}`,
35+
{
36+
headers: {
37+
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
38+
Accepts: "application/json",
39+
},
40+
}
41+
);
42+
43+
if (!response.ok) {
44+
createApiError(response);
45+
}
46+
47+
const data = await response.json();
48+
49+
return {
50+
...(params?.additionalFields && pick(data, params.additionalFields)),
51+
id: data._id,
52+
name: data.id,
53+
private: data.private,
54+
task: data.pipeline_tag,
55+
downloads: data.downloads,
56+
gated: data.gated,
57+
likes: data.likes,
58+
updatedAt: new Date(data.lastModified),
59+
} as ModelEntry & Pick<ApiModelInfo, T>;
60+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { describe, expect, it } from "vitest";
2+
import { spaceInfo } from "./space-info";
3+
4+
describe("spaceInfo", () => {
5+
it("should return the space info", async () => {
6+
const info = await spaceInfo({
7+
name: "huggingfacejs/client-side-oauth",
8+
});
9+
expect(info).toEqual({
10+
id: "659835e689010f9c7aed608d",
11+
name: "huggingfacejs/client-side-oauth",
12+
updatedAt: expect.any(Date),
13+
likes: expect.any(Number),
14+
private: false,
15+
sdk: "static",
16+
});
17+
});
18+
});

packages/hub/src/lib/space-info.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { HUB_URL } from "../consts";
2+
import { createApiError } from "../error";
3+
import type { ApiSpaceInfo } from "../types/api/api-space";
4+
import type { CredentialsParams } from "../types/public";
5+
import { checkCredentials } from "../utils/checkCredentials";
6+
import { pick } from "../utils/pick";
7+
import type { SPACE_EXPANDABLE_KEYS, SpaceEntry } from "./list-spaces";
8+
import { SPACE_EXPAND_KEYS } from "./list-spaces";
9+
10+
export async function spaceInfo<
11+
const T extends Exclude<(typeof SPACE_EXPANDABLE_KEYS)[number], (typeof SPACE_EXPAND_KEYS)[number]> = never,
12+
>(
13+
params: {
14+
name: string;
15+
hubUrl?: string;
16+
additionalFields?: T[];
17+
/**
18+
* Set to limit the number of models returned.
19+
*/
20+
limit?: number;
21+
/**
22+
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
23+
*/
24+
fetch?: typeof fetch;
25+
} & Partial<CredentialsParams>
26+
): Promise<SpaceEntry & Pick<ApiSpaceInfo, T>> {
27+
const accessToken = params && checkCredentials(params);
28+
29+
const search = new URLSearchParams([
30+
...SPACE_EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
31+
...(params?.additionalFields?.map((val) => ["expand", val] satisfies [string, string]) ?? []),
32+
]).toString();
33+
34+
const response = await (params.fetch || fetch)(
35+
`${params?.hubUrl || HUB_URL}/api/spaces/${params.name}?${search.toString()}`,
36+
{
37+
headers: {
38+
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
39+
Accepts: "application/json",
40+
},
41+
}
42+
);
43+
44+
if (!response.ok) {
45+
createApiError(response);
46+
}
47+
48+
const data = await response.json();
49+
50+
return {
51+
...(params?.additionalFields && pick(data, params.additionalFields)),
52+
id: data._id,
53+
name: data.id,
54+
sdk: data.sdk,
55+
likes: data.likes,
56+
private: data.private,
57+
updatedAt: new Date(data.lastModified),
58+
} as SpaceEntry & Pick<ApiSpaceInfo, T>;
59+
}

0 commit comments

Comments
 (0)