From fc57b44556f87b747ec6c0901b0690b506aacde5 Mon Sep 17 00:00:00 2001 From: Mishig Date: Mon, 28 Oct 2024 11:16:50 +0100 Subject: [PATCH 01/97] [Inference snippets] VLM hf_hub, oai snippets (#985) Thanks to https://github.com/huggingface/huggingface.js/pull/976, now we can show `hf_hub`, `oai` snippets for VLMs ("conversational image-text-to-text" models). --- packages/tasks/src/snippets/curl.ts | 51 ++++++++++---------------- packages/tasks/src/snippets/js.ts | 53 ++++++++++----------------- packages/tasks/src/snippets/python.ts | 52 ++++++++++---------------- 3 files changed, 58 insertions(+), 98 deletions(-) diff --git a/packages/tasks/src/snippets/curl.ts b/packages/tasks/src/snippets/curl.ts index a6bdfcb15..9dac94f50 100644 --- a/packages/tasks/src/snippets/curl.ts +++ b/packages/tasks/src/snippets/curl.ts @@ -26,9 +26,24 @@ export const snippetTextGeneration = ( if (model.tags.includes("conversational")) { // Conversational model detected, so we display a code snippet that features the Messages API const streaming = opts?.streaming ?? true; - const messages: ChatCompletionInputMessage[] = opts?.messages ?? [ - { role: "user", content: "What is the capital of France?" }, - ]; + const exampleMessages: ChatCompletionInputMessage[] = + model.pipeline_tag === "text-generation" + ? [{ role: "user", content: "What is the capital of France?" }] + : [ + { + role: "user", + content: [ + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", + }, + }, + { type: "text", text: "Describe this image in one sentence." }, + ], + }, + ]; + const messages = opts?.messages ?? exampleMessages; const config = { ...(opts?.temperature ? { temperature: opts.temperature } : undefined), @@ -63,34 +78,6 @@ export const snippetTextGeneration = ( } }; -export const snippetImageTextToTextGeneration = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => { - if (model.tags.includes("conversational")) { - // Conversational model detected, so we display a code snippet that features the Messages API - return { - content: `curl 'https://api-inference.huggingface.co/models/${model.id}/v1/chat/completions' \\ --H "Authorization: Bearer ${accessToken || `{API_TOKEN}`}" \\ --H 'Content-Type: application/json' \\ --d '{ - "model": "${model.id}", - "messages": [ - { - "role": "user", - "content": [ - {"type": "image_url", "image_url": {"url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg"}}, - {"type": "text", "text": "Describe this image in one sentence."} - ] - } - ], - "max_tokens": 500, - "stream": false -}' -`, - }; - } else { - return snippetBasic(model, accessToken); - } -}; - export const snippetZeroShotClassification = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => ({ content: `curl https://api-inference.huggingface.co/models/${model.id} \\ -X POST \\ @@ -122,7 +109,7 @@ export const curlSnippets: Partial< summarization: snippetBasic, "feature-extraction": snippetBasic, "text-generation": snippetTextGeneration, - "image-text-to-text": snippetImageTextToTextGeneration, + "image-text-to-text": snippetTextGeneration, "text2text-generation": snippetBasic, "fill-mask": snippetBasic, "sentence-similarity": snippetBasic, diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index f735ca912..4445af389 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -40,9 +40,24 @@ export const snippetTextGeneration = ( if (model.tags.includes("conversational")) { // Conversational model detected, so we display a code snippet that features the Messages API const streaming = opts?.streaming ?? true; - const messages: ChatCompletionInputMessage[] = opts?.messages ?? [ - { role: "user", content: "What is the capital of France?" }, - ]; + const exampleMessages: ChatCompletionInputMessage[] = + model.pipeline_tag === "text-generation" + ? [{ role: "user", content: "What is the capital of France?" }] + : [ + { + role: "user", + content: [ + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", + }, + }, + { type: "text", text: "Describe this image in one sentence." }, + ], + }, + ]; + const messages = opts?.messages ?? exampleMessages; const messagesStr = stringifyMessages(messages, { sep: ",\n\t\t", start: "[\n\t\t", end: "\n\t]" }); const config = { @@ -148,36 +163,6 @@ console.log(chatCompletion.choices[0].message);`, } }; -export const snippetImageTextToTextGeneration = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => { - if (model.tags.includes("conversational")) { - // Conversational model detected, so we display a code snippet that features the Messages API - return { - content: `import { HfInference } from "@huggingface/inference"; - -const inference = new HfInference("${accessToken || `{API_TOKEN}`}"); -const imageUrl = "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg"; - -for await (const chunk of inference.chatCompletionStream({ - model: "${model.id}", - messages: [ - { - "role": "user", - "content": [ - {"type": "image_url", "image_url": {"url": imageUrl}}, - {"type": "text", "text": "Describe this image in one sentence."}, - ], - } - ], - max_tokens: 500, -})) { - process.stdout.write(chunk.choices[0]?.delta?.content || ""); -}`, - }; - } else { - return snippetBasic(model, accessToken); - } -}; - export const snippetZeroShotClassification = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => ({ content: `async function query(data) { const response = await fetch( @@ -307,7 +292,7 @@ export const jsSnippets: Partial< summarization: snippetBasic, "feature-extraction": snippetBasic, "text-generation": snippetTextGeneration, - "image-text-to-text": snippetImageTextToTextGeneration, + "image-text-to-text": snippetTextGeneration, "text2text-generation": snippetBasic, "fill-mask": snippetBasic, "sentence-similarity": snippetBasic, diff --git a/packages/tasks/src/snippets/python.ts b/packages/tasks/src/snippets/python.ts index 2cb69693e..af8c658c3 100644 --- a/packages/tasks/src/snippets/python.ts +++ b/packages/tasks/src/snippets/python.ts @@ -16,9 +16,24 @@ export const snippetConversational = ( } ): InferenceSnippet[] => { const streaming = opts?.streaming ?? true; - const messages: ChatCompletionInputMessage[] = opts?.messages ?? [ - { role: "user", content: "What is the capital of France?" }, - ]; + const exampleMessages: ChatCompletionInputMessage[] = + model.pipeline_tag === "text-generation" + ? [{ role: "user", content: "What is the capital of France?" }] + : [ + { + role: "user", + content: [ + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", + }, + }, + { type: "text", text: "Describe this image in one sentence." }, + ], + }, + ]; + const messages = opts?.messages ?? exampleMessages; const messagesStr = stringifyMessages(messages, { sep: ",\n\t", start: `[\n\t`, @@ -121,30 +136,6 @@ print(completion.choices[0].message)`, } }; -export const snippetConversationalWithImage = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => ({ - content: `from huggingface_hub import InferenceClient - -client = InferenceClient(api_key="${accessToken || "{API_TOKEN}"}") - -image_url = "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" - -for message in client.chat_completion( - model="${model.id}", - messages=[ - { - "role": "user", - "content": [ - {"type": "image_url", "image_url": {"url": image_url}}, - {"type": "text", "text": "Describe this image in one sentence."}, - ], - } - ], - max_tokens=500, - stream=True, -): - print(message.choices[0].delta.content, end="")`, -}); - export const snippetZeroShotClassification = (model: ModelDataMinimal): InferenceSnippet => ({ content: `def query(payload): response = requests.post(API_URL, headers=headers, json=payload) @@ -282,7 +273,7 @@ export const pythonSnippets: Partial< "feature-extraction": snippetBasic, "text-generation": snippetBasic, "text2text-generation": snippetBasic, - "image-text-to-text": snippetConversationalWithImage, + "image-text-to-text": snippetConversational, "fill-mask": snippetBasic, "sentence-similarity": snippetBasic, "automatic-speech-recognition": snippetFile, @@ -306,12 +297,9 @@ export function getPythonInferenceSnippet( accessToken: string, opts?: Record ): InferenceSnippet | InferenceSnippet[] { - if (model.pipeline_tag === "text-generation" && model.tags.includes("conversational")) { + if (model.tags.includes("conversational")) { // Conversational model detected, so we display a code snippet that features the Messages API return snippetConversational(model, accessToken, opts); - } else if (model.pipeline_tag === "image-text-to-text" && model.tags.includes("conversational")) { - // Example sending an image to the Message API - return snippetConversationalWithImage(model, accessToken); } else { let snippets = model.pipeline_tag && model.pipeline_tag in pythonSnippets From 850a70e2f3cd4dba832d08fb4b4a158e9069297c Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 28 Oct 2024 10:17:41 +0000 Subject: [PATCH 02/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.12.?= =?UTF-8?q?27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index baf2d918f..556eb86f4 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.12.26", + "version": "0.12.27", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From ed5a33a7b4f14b52b06b592d6f6cc3551b68610e Mon Sep 17 00:00:00 2001 From: NielsRogge <48327001+NielsRogge@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:39:44 +0100 Subject: [PATCH 03/97] Add "mini-omni2" as a library (#984) This PR makes sure download stats work for https://huggingface.co/gpt-omni/mini-omni2. --------- Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index ca2cc7cbb..6de832261 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -373,6 +373,12 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { repoUrl: "https://github.com/abetlen/llama-cpp-python", snippets: snippets.llama_cpp_python, }, + "mini-omni2": { + prettyLabel: "Mini-Omni2", + repoName: "Mini-Omni2", + repoUrl: "https://github.com/gpt-omni/mini-omni2", + countDownloads: `path:"model_config.yaml"`, + }, mindspore: { prettyLabel: "MindSpore", repoName: "mindspore", From c8c982ef2718970326fee2090f6aded9d33e7d2a Mon Sep 17 00:00:00 2001 From: Pedro Cuenca Date: Tue, 29 Oct 2024 10:35:09 +0100 Subject: [PATCH 04/97] Lint fixes (#990) --- packages/tasks/src/tasks/image-segmentation/data.ts | 3 +-- packages/tasks/src/tasks/object-detection/data.ts | 3 +-- packages/tasks/src/tasks/text-to-speech/data.ts | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/tasks/src/tasks/image-segmentation/data.ts b/packages/tasks/src/tasks/image-segmentation/data.ts index edbd100ea..5469a30d2 100644 --- a/packages/tasks/src/tasks/image-segmentation/data.ts +++ b/packages/tasks/src/tasks/image-segmentation/data.ts @@ -44,8 +44,7 @@ const taskData: TaskDataCustom = { models: [ { // TO DO: write description - description: - "Solid semantic segmentation model trained on ADE20k.", + description: "Solid semantic segmentation model trained on ADE20k.", id: "openmmlab/upernet-convnext-small", }, { diff --git a/packages/tasks/src/tasks/object-detection/data.ts b/packages/tasks/src/tasks/object-detection/data.ts index 80f87a590..840f7a431 100644 --- a/packages/tasks/src/tasks/object-detection/data.ts +++ b/packages/tasks/src/tasks/object-detection/data.ts @@ -51,8 +51,7 @@ const taskData: TaskDataCustom = { id: "jameslahm/yolov10x", }, { - description: - "Fast and accurate object detection model trained on COCO and Object365 datasets.", + description: "Fast and accurate object detection model trained on COCO and Object365 datasets.", id: "PekingU/rtdetr_r18vd_coco_o365", }, ], diff --git a/packages/tasks/src/tasks/text-to-speech/data.ts b/packages/tasks/src/tasks/text-to-speech/data.ts index 43a69ce4c..464a39afc 100644 --- a/packages/tasks/src/tasks/text-to-speech/data.ts +++ b/packages/tasks/src/tasks/text-to-speech/data.ts @@ -57,7 +57,8 @@ const taskData: TaskDataCustom = { id: "suno/bark", }, { - description: "An application on XTTS, a voice generation model that lets you clone voices into different languages.", + description: + "An application on XTTS, a voice generation model that lets you clone voices into different languages.", id: "coqui/xtts", }, { From 4ec0384bb1b08b45590ba7783eebbd3645d84f2d Mon Sep 17 00:00:00 2001 From: Lucain Date: Tue, 29 Oct 2024 11:13:41 +0100 Subject: [PATCH 05/97] Switch to securityFileStatus (fix failing ci) (#991) This PR fixes the failing CI: - ~some formatting issues in `packages/tasks`~ already done in https://github.com/huggingface/huggingface.js/pull/990 - in `listFiles`, `entry.security` has been replaced by `entry.securityFileStatus` server-side. This PR updates the data structure + test to address this change. Expectation: green CI :smile: --- packages/hub/src/lib/list-files.spec.ts | 2 +- packages/hub/src/lib/list-files.ts | 4 ++-- packages/hub/src/types/api/api-commit.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hub/src/lib/list-files.spec.ts b/packages/hub/src/lib/list-files.spec.ts index 83b4438b3..ee59a78a0 100644 --- a/packages/hub/src/lib/list-files.spec.ts +++ b/packages/hub/src/lib/list-files.spec.ts @@ -75,7 +75,7 @@ describe("listFiles", () => { const files: ListFileEntry[] = []; for await (const entry of cursor) { - delete entry.security; // flaky + delete entry.securityFileStatus; // flaky files.push(entry); } diff --git a/packages/hub/src/lib/list-files.ts b/packages/hub/src/lib/list-files.ts index 3083e9587..1648bfe60 100644 --- a/packages/hub/src/lib/list-files.ts +++ b/packages/hub/src/lib/list-files.ts @@ -28,7 +28,7 @@ export interface ListFileEntry { /** * Only fetched if `expand` is set to `true` in the `listFiles` call. */ - security?: unknown; + securityFileStatus?: unknown; } /** @@ -48,7 +48,7 @@ export async function* listFiles( */ path?: string; /** - * Fetch `lastCommit` and `securityStatus` for each file. + * Fetch `lastCommit` and `securityFileStatus` for each file. */ expand?: boolean; revision?: string; diff --git a/packages/hub/src/types/api/api-commit.ts b/packages/hub/src/types/api/api-commit.ts index 404ad5494..b5fbfec4b 100644 --- a/packages/hub/src/types/api/api-commit.ts +++ b/packages/hub/src/types/api/api-commit.ts @@ -5,7 +5,7 @@ export interface ApiLfsBatchRequest { /** * Optional object describing the server ref that the objects belong to. Note: Added in v2.4. * - * We use this object for QOL and to fail early for users when they're tring to push to the wrong reference. + * We use this object for QOL and to fail early for users when they're trying to push to the wrong reference. * But it does nothing for security. */ ref?: { From e14e8c116fe5d4f9d522508d18a63a0bfb02cb91 Mon Sep 17 00:00:00 2001 From: Merve Noyan Date: Tue, 29 Oct 2024 11:56:12 +0100 Subject: [PATCH 06/97] Tasks: reorder tasks in main page (#987) --------- Co-authored-by: Lucain --- packages/tasks/src/pipelines.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/src/pipelines.ts b/packages/tasks/src/pipelines.ts index 34907f064..237469b89 100644 --- a/packages/tasks/src/pipelines.ts +++ b/packages/tasks/src/pipelines.ts @@ -1,4 +1,4 @@ -export const MODALITIES = ["cv", "nlp", "audio", "tabular", "multimodal", "rl", "other"] as const; +export const MODALITIES = ["multimodal", "nlp", "cv", "audio", "tabular", "rl", "other"] as const; export type Modality = (typeof MODALITIES)[number]; From f93f6a421a2c921903183339b1876b18155dbb64 Mon Sep 17 00:00:00 2001 From: Mishig Date: Tue, 29 Oct 2024 12:55:04 +0100 Subject: [PATCH 07/97] Refactor conversational input to getModelInputSnippet (#989) Refactor conversational input to getModelInputSnippet. Follow up to comment https://github.com/huggingface/huggingface.js/pull/985#discussion_r1816669341 @Wauplin --- packages/tasks/src/snippets/curl.ts | 18 +--------- packages/tasks/src/snippets/inputs.ts | 50 +++++++++++++++++++++------ packages/tasks/src/snippets/js.ts | 18 +--------- packages/tasks/src/snippets/python.ts | 18 +--------- 4 files changed, 43 insertions(+), 61 deletions(-) diff --git a/packages/tasks/src/snippets/curl.ts b/packages/tasks/src/snippets/curl.ts index 9dac94f50..af4ada267 100644 --- a/packages/tasks/src/snippets/curl.ts +++ b/packages/tasks/src/snippets/curl.ts @@ -26,23 +26,7 @@ export const snippetTextGeneration = ( if (model.tags.includes("conversational")) { // Conversational model detected, so we display a code snippet that features the Messages API const streaming = opts?.streaming ?? true; - const exampleMessages: ChatCompletionInputMessage[] = - model.pipeline_tag === "text-generation" - ? [{ role: "user", content: "What is the capital of France?" }] - : [ - { - role: "user", - content: [ - { - type: "image_url", - image_url: { - url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", - }, - }, - { type: "text", text: "Describe this image in one sentence." }, - ], - }, - ]; + const exampleMessages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; const messages = opts?.messages ?? exampleMessages; const config = { diff --git a/packages/tasks/src/snippets/inputs.ts b/packages/tasks/src/snippets/inputs.ts index f3c76d12c..6a0404bdf 100644 --- a/packages/tasks/src/snippets/inputs.ts +++ b/packages/tasks/src/snippets/inputs.ts @@ -1,4 +1,5 @@ import type { PipelineType } from "../pipelines"; +import type { ChatCompletionInputMessage } from "../tasks"; import type { ModelDataMinimal } from "./types"; const inputsZeroShotClassification = () => @@ -40,7 +41,30 @@ const inputsTextClassification = () => `"I like you. I love you"`; const inputsTokenClassification = () => `"My name is Sarah Jessica Parker but you can call me Jessica"`; -const inputsTextGeneration = () => `"Can you please let us know more details about your "`; +const inputsTextGeneration = (model: ModelDataMinimal): string | ChatCompletionInputMessage[] => { + if (model.tags.includes("conversational")) { + return model.pipeline_tag === "text-generation" + ? [{ role: "user", content: "What is the capital of France?" }] + : [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence.", + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", + }, + }, + ], + }, + ]; + } + return `"Can you please let us know more details about your "`; +}; const inputsText2TextGeneration = () => `"The answer to the universe is"`; @@ -84,7 +108,7 @@ const inputsTabularPrediction = () => const inputsZeroShotImageClassification = () => `"cats.jpg"`; const modelInputSnippets: { - [key in PipelineType]?: (model: ModelDataMinimal) => string; + [key in PipelineType]?: (model: ModelDataMinimal) => string | ChatCompletionInputMessage[]; } = { "audio-to-audio": inputsAudioToAudio, "audio-classification": inputsAudioClassification, @@ -116,18 +140,24 @@ const modelInputSnippets: { // Use noWrap to put the whole snippet on a single line (removing new lines and tabulations) // Use noQuotes to strip quotes from start & end (example: "abc" -> abc) -export function getModelInputSnippet(model: ModelDataMinimal, noWrap = false, noQuotes = false): string { +export function getModelInputSnippet( + model: ModelDataMinimal, + noWrap = false, + noQuotes = false +): string | ChatCompletionInputMessage[] { if (model.pipeline_tag) { const inputs = modelInputSnippets[model.pipeline_tag]; if (inputs) { let result = inputs(model); - if (noWrap) { - result = result.replace(/(?:(?:\r?\n|\r)\t*)|\t+/g, " "); - } - if (noQuotes) { - const REGEX_QUOTES = /^"(.+)"$/s; - const match = result.match(REGEX_QUOTES); - result = match ? match[1] : result; + if (typeof result === "string") { + if (noWrap) { + result = result.replace(/(?:(?:\r?\n|\r)\t*)|\t+/g, " "); + } + if (noQuotes) { + const REGEX_QUOTES = /^"(.+)"$/s; + const match = result.match(REGEX_QUOTES); + result = match ? match[1] : result; + } } return result; } diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index 4445af389..c261e08a1 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -40,23 +40,7 @@ export const snippetTextGeneration = ( if (model.tags.includes("conversational")) { // Conversational model detected, so we display a code snippet that features the Messages API const streaming = opts?.streaming ?? true; - const exampleMessages: ChatCompletionInputMessage[] = - model.pipeline_tag === "text-generation" - ? [{ role: "user", content: "What is the capital of France?" }] - : [ - { - role: "user", - content: [ - { - type: "image_url", - image_url: { - url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", - }, - }, - { type: "text", text: "Describe this image in one sentence." }, - ], - }, - ]; + const exampleMessages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; const messages = opts?.messages ?? exampleMessages; const messagesStr = stringifyMessages(messages, { sep: ",\n\t\t", start: "[\n\t\t", end: "\n\t]" }); diff --git a/packages/tasks/src/snippets/python.ts b/packages/tasks/src/snippets/python.ts index af8c658c3..d2b0f2585 100644 --- a/packages/tasks/src/snippets/python.ts +++ b/packages/tasks/src/snippets/python.ts @@ -16,23 +16,7 @@ export const snippetConversational = ( } ): InferenceSnippet[] => { const streaming = opts?.streaming ?? true; - const exampleMessages: ChatCompletionInputMessage[] = - model.pipeline_tag === "text-generation" - ? [{ role: "user", content: "What is the capital of France?" }] - : [ - { - role: "user", - content: [ - { - type: "image_url", - image_url: { - url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg", - }, - }, - { type: "text", text: "Describe this image in one sentence." }, - ], - }, - ]; + const exampleMessages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; const messages = opts?.messages ?? exampleMessages; const messagesStr = stringifyMessages(messages, { sep: ",\n\t", From 8458be9f221950e809c88d421d4d58214bbf2ed7 Mon Sep 17 00:00:00 2001 From: machineuser Date: Tue, 29 Oct 2024 13:18:30 +0000 Subject: [PATCH 08/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.12.?= =?UTF-8?q?28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 556eb86f4..318365a7f 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.12.27", + "version": "0.12.28", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From dd1befa8b4a48d91e256806b7a29de453514e1f2 Mon Sep 17 00:00:00 2001 From: Mishig Date: Tue, 29 Oct 2024 14:52:11 +0100 Subject: [PATCH 09/97] [VLM] snippet fix: add missing brackets (#992) Follow up to https://github.com/huggingface/huggingface.js/pull/989 --- packages/tasks/src/snippets/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/src/snippets/common.ts b/packages/tasks/src/snippets/common.ts index b0fe4bef5..24b061340 100644 --- a/packages/tasks/src/snippets/common.ts +++ b/packages/tasks/src/snippets/common.ts @@ -30,7 +30,7 @@ export function stringifyMessages(messages: ChatCompletionInputMessage[], opts: if (opts.customContentEscaper) { content = opts.customContentEscaper(content); } - return `{ ${keyRole}: "${role}", ${keyContent}: ${content} }`; + return `{ ${keyRole}: "${role}", ${keyContent}: [${content}] }`; } }); From ff46cba15a4754469f1380ad60e95ec37f194230 Mon Sep 17 00:00:00 2001 From: Joshua Lochner Date: Wed, 30 Oct 2024 12:43:06 +0200 Subject: [PATCH 10/97] [jinja] Add `is mapping` test (#995) Closes #993 --- packages/jinja/src/runtime.ts | 3 +- packages/jinja/test/e2e.test.js | 158 ++++++++++++++++---------- packages/jinja/test/templates.test.js | 35 ++++++ 3 files changed, 135 insertions(+), 61 deletions(-) diff --git a/packages/jinja/src/runtime.ts b/packages/jinja/src/runtime.ts index a35221c0a..05688f277 100644 --- a/packages/jinja/src/runtime.ts +++ b/packages/jinja/src/runtime.ts @@ -274,7 +274,8 @@ export class Environment { ["string", (operand) => operand.type === "StringValue"], ["number", (operand) => operand.type === "NumericValue"], ["integer", (operand) => operand.type === "NumericValue" && Number.isInteger((operand as NumericValue).value)], - ["iterable", (operand) => operand instanceof ArrayValue || operand instanceof StringValue], + ["iterable", (operand) => operand.type === "ArrayValue" || operand.type === "StringValue"], + ["mapping", (operand) => operand.type === "ObjectValue"], [ "lower", (operand) => { diff --git a/packages/jinja/test/e2e.test.js b/packages/jinja/test/e2e.test.js index fe588e330..7de154a54 100644 --- a/packages/jinja/test/e2e.test.js +++ b/packages/jinja/test/e2e.test.js @@ -76,15 +76,8 @@ const EXAMPLE_FUNCTION_CALLING_WITH_SYSTEM = [ { role: "user", content: "Hi, can you tell me the current stock price of AAPL?" }, ]; -// Adapted from https://huggingface.co/CISCai/Mistral-7B-Instruct-v0.3-SOTA-GGUF -const EXAMPLE_CHAT_WITH_TOOLS = [ - { - role: "user", - content: "What's the weather like in Oslo and Stockholm?", - }, -]; -const EXAMPLE_TOOLS = [ - { +const EXAMPLE_TOOL_JSON_SCHEMAS = { + get_current_weather: { type: "function", function: { name: "get_current_weather", @@ -105,7 +98,81 @@ const EXAMPLE_TOOLS = [ }, }, }, + get_current_temperature_v1: { + type: "function", + function: { + name: "get_current_temperature", + description: "Get the current temperature at a location.", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: 'The location to get the temperature for, in the format "City, Country"', + }, + }, + required: ["location"], + }, + return: { + type: "number", + description: "The current temperature at the specified location in the specified units, as a float.", + }, + }, + }, + get_current_temperature_v2: { + type: "function", + function: { + name: "get_current_temperature", + description: "Get the current temperature at a location.", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: 'The location to get the temperature for, in the format "City, Country"', + }, + unit: { + type: "string", + enum: ["celsius", "fahrenheit"], + description: "The unit to return the temperature in.", + }, + }, + required: ["location", "unit"], + }, + return: { + type: "number", + description: "The current temperature at the specified location in the specified units, as a float.", + }, + }, + }, + get_current_wind_speed: { + type: "function", + function: { + name: "get_current_wind_speed", + description: "Get the current wind speed in km/h at a given location.", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: 'The location to get the temperature for, in the format "City, Country"', + }, + }, + required: ["location"], + }, + return: { + type: "number", + description: "The current wind speed at the given location in km/h, as a float.", + }, + }, + }, +}; + +const EXAMPLE_LIST_OF_TOOLS = [ + EXAMPLE_TOOL_JSON_SCHEMAS.get_current_temperature_v2, + EXAMPLE_TOOL_JSON_SCHEMAS.get_current_wind_speed, ]; + /** * Defined in https://github.com/huggingface/transformers * Keys correspond to `model_type` in the transformers repo. @@ -532,55 +599,7 @@ const TEST_CUSTOM_TEMPLATES = Object.freeze({ }, { role: "tool", tool_call_id: "abcdef123", name: "get_current_temperature", content: "22.0" }, ], - tools: [ - { - type: "function", - function: { - name: "get_current_temperature", - description: "Get the current temperature at a location.", - parameters: { - type: "object", - properties: { - location: { - type: "string", - description: 'The location to get the temperature for, in the format "City, Country"', - }, - unit: { - type: "string", - enum: ["celsius", "fahrenheit"], - description: "The unit to return the temperature in.", - }, - }, - required: ["location", "unit"], - }, - return: { - type: "number", - description: "The current temperature at the specified location in the specified units, as a float.", - }, - }, - }, - { - type: "function", - function: { - name: "get_current_wind_speed", - description: "Get the current wind speed in km/h at a given location.", - parameters: { - type: "object", - properties: { - location: { - type: "string", - description: 'The location to get the temperature for, in the format "City, Country"', - }, - }, - required: ["location"], - }, - return: { - type: "number", - description: "The current wind speed at the given location in km/h, as a float.", - }, - }, - }, - ], + tools: EXAMPLE_LIST_OF_TOOLS, bos_token: "", eos_token: "", }, @@ -590,8 +609,13 @@ const TEST_CUSTOM_TEMPLATES = Object.freeze({ "CISCai/Mistral-7B-Instruct-v0.3-SOTA-GGUF": { chat_template: `{{ bos_token }}{% set ns = namespace(lastuser=-1, system=false, functions=false) %}{% if tools %}{% for message in messages %}{% if message['role'] == 'user' %}{% set ns.lastuser = loop.index0 %}{% elif message['role'] == 'system' %}{% set ns.system = message['content'] %}{% endif %}{% endfor %}{% set ns.functions = tools|selectattr('type','eq','function')|map(attribute='function')|list|tojson %}{% endif %}{% for message in messages %}{% if message['role'] == 'user' %}{% if loop.index0 == ns.lastuser and ns.functions %}{{ '[AVAILABLE_TOOLS] ' }}{{ ns.functions }}{{ '[/AVAILABLE_TOOLS]' }}{% endif %}{{ '[INST] ' }}{% if loop.index0 == ns.lastuser and ns.system %}{{ ns.system + ' ' }}{% endif %}{{ message['content'] }}{{ '[/INST]' }}{% elif message['role'] == 'tool' %}{{ '[TOOL_RESULTS] ' }}{{ dict(call_id=message['tool_call_id'], content=message['content'])|tojson }}{{ '[/TOOL_RESULTS]' }}{% elif message['role'] == 'assistant' %}{% if message['tool_calls'] %}{{ '[TOOL_CALLS] [' }}{% for call in message['tool_calls'] %}{% if call['type'] == 'function' %}{{ dict(id=call['id'], name=call['function']['name'], arguments=call['function']['arguments'])|tojson }}{% endif %}{% if not loop.last %}{{ ', ' }}{% endif %}{% endfor %}{{ ']' }}{% else %}{{ message['content'] }}{% endif %}{{ eos_token }}{% endif %}{% endfor %}`, data: { - messages: EXAMPLE_CHAT_WITH_TOOLS, - tools: EXAMPLE_TOOLS, + messages: [ + { + role: "user", + content: "What's the weather like in Oslo and Stockholm?", + }, + ], + tools: [EXAMPLE_TOOL_JSON_SCHEMAS.get_current_weather], bos_token: "", eos_token: "", }, @@ -630,6 +654,20 @@ const TEST_CUSTOM_TEMPLATES = Object.freeze({ }, target: `<|begin_of_text|>You are a function calling AI model. You are provided with function signatures within XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: {"type": "function", "function": {"name": get_stock_fundamentals", "description": "get_stock_fundamentals(symbol: str) -> dict - Get fundamental data for a given stock symbol using yfinance API.\n\n Args:\n symbol(str): The stock symbol.\n Returns:\n A dictionary containing fundamental data.\n\nKeys:\n - 'symbol': The stock symbol.\n - 'company_name': The long name of the company.\n - 'sector': The sector to which the company belongs.\n - 'industry': The industry to which the company belongs.\n - 'market_cap': The market capitalization of the company.\n - 'pe_ratio': The forward price-to-earnings ratio.\n - 'pb_ratio': The price-to-book ratio.\n - 'dividend_yield': The dividend yield.\n - 'eps': The trailing earnings per share.\n - 'beta': The beta value of the stock.\n - '52_week_high': The 52-week high price of the stock.\n - '52_week_low': The 52-week low price of the stock.", "parameters": {"type": "object", "properties": {"symbol": {"type": "string", "description": "The stock symbol."}}, "required": ["symbol"]}} Use the following pydantic model json schema for each tool call you will make: {"properties": {"arguments": {"title": "Arguments", "type": "object"}, "name": {"title": "Name", "type": "string"}}, "required": ["arguments", "name"], "title": "FunctionCall", "type": "object"}\nFor each function call return a json object with function name and arguments within XML tags as follows:\n\n{"arguments": , "name": }\n<|im_end|><|im_start|>user\nFetch the stock fundamentals data for Tesla (TSLA)<|im_end|>\n<|im_start|>assistant\n`, }, + "meta-llama/Llama-3.1-8B-Instruct": { + chat_template: `{{- bos_token }}\n{%- if custom_tools is defined %}\n {%- set tools = custom_tools %}\n{%- endif %}\n{%- if not tools_in_user_message is defined %}\n {%- set tools_in_user_message = true %}\n{%- endif %}\n{%- if not date_string is defined %}\n {%- set date_string = "26 Jul 2024" %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n\n{#- This block extracts the system message, so we can slot it into the right place. #}\n{%- if messages[0]['role'] == 'system' %}\n {%- set system_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n{%- else %}\n {%- set system_message = "" %}\n{%- endif %}\n\n{#- System message + builtin tools #}\n{{- "<|start_header_id|>system<|end_header_id|>\\n\\n" }}\n{%- if builtin_tools is defined or tools is not none %}\n {{- "Environment: ipython\\n" }}\n{%- endif %}\n{%- if builtin_tools is defined %}\n {{- "Tools: " + builtin_tools | reject('equalto', 'code_interpreter') | join(", ") + "\\n\\n"}}\n{%- endif %}\n{{- "Cutting Knowledge Date: December 2023\\n" }}\n{{- "Today Date: " + date_string + "\\n\\n" }}\n{%- if tools is not none and not tools_in_user_message %}\n {{- "You have access to the following functions. To call a function, please respond with JSON for a function call." }}\n {{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}\n {{- "Do not use variables.\\n\\n" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- "\\n\\n" }}\n {%- endfor %}\n{%- endif %}\n{{- system_message }}\n{{- "<|eot_id|>" }}\n\n{#- Custom tools are passed in a user message with some extra guidance #}\n{%- if tools_in_user_message and not tools is none %}\n {#- Extract the first user message so we can plug it in here #}\n {%- if messages | length != 0 %}\n {%- set first_user_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n {%- else %}\n {{- raise_exception("Cannot put tools in the first user message when there's no first user message!") }}\n{%- endif %}\n {{- '<|start_header_id|>user<|end_header_id|>\\n\\n' -}}\n {{- "Given the following functions, please respond with a JSON for a function call " }}\n {{- "with its proper arguments that best answers the given prompt.\\n\\n" }}\n {{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}\n {{- "Do not use variables.\\n\\n" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- "\\n\\n" }}\n {%- endfor %}\n {{- first_user_message + "<|eot_id|>"}}\n{%- endif %}\n\n{%- for message in messages %}\n {%- if not (message.role == 'ipython' or message.role == 'tool' or 'tool_calls' in message) %}\n {{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\\n\\n'+ message['content'] | trim + '<|eot_id|>' }}\n {%- elif 'tool_calls' in message %}\n {%- if not message.tool_calls|length == 1 %}\n {{- raise_exception("This model only supports single tool-calls at once!") }}\n {%- endif %}\n {%- set tool_call = message.tool_calls[0].function %}\n {%- if builtin_tools is defined and tool_call.name in builtin_tools %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- "<|python_tag|>" + tool_call.name + ".call(" }}\n {%- for arg_name, arg_val in tool_call.arguments | items %}\n {{- arg_name + '="' + arg_val + '"' }}\n {%- if not loop.last %}\n {{- ", " }}\n {%- endif %}\n {%- endfor %}\n {{- ")" }}\n {%- else %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- '{"name": "' + tool_call.name + '", ' }}\n {{- '"parameters": ' }}\n {{- tool_call.arguments | tojson }}\n {{- "}" }}\n {%- endif %}\n {%- if builtin_tools is defined %}\n {#- This means we're in ipython mode #}\n {{- "<|eom_id|>" }}\n {%- else %}\n {{- "<|eot_id|>" }}\n {%- endif %}\n {%- elif message.role == "tool" or message.role == "ipython" %}\n {{- "<|start_header_id|>ipython<|end_header_id|>\\n\\n" }}\n {%- if message.content is mapping or message.content is iterable %}\n {{- message.content | tojson }}\n {%- else %}\n {{- message.content }}\n {%- endif %}\n {{- "<|eot_id|>" }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' }}\n{%- endif %}\n`, + data: { + messages: [ + { role: "system", content: "You are a bot that responds to weather queries." }, + { role: "user", content: "Hey, what's the temperature in Paris right now?" }, + ], + tools: [EXAMPLE_TOOL_JSON_SCHEMAS.get_current_temperature_v1], + bos_token: "<|begin_of_text|>", + eos_token: "<|im_end|>", + add_generation_prompt: true, + }, + target: `<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nEnvironment: ipython\nCutting Knowledge Date: December 2023\nToday Date: 26 Jul 2024\n\nYou are a bot that responds to weather queries.<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nGiven the following functions, please respond with a JSON for a function call with its proper arguments that best answers the given prompt.\n\nRespond in the format {"name": function name, "parameters": dictionary of argument name and its value}.Do not use variables.\n\n{\n "type": "function",\n "function": {\n "name": "get_current_temperature",\n "description": "Get the current temperature at a location.",\n "parameters": {\n "type": "object",\n "properties": {\n "location": {\n "type": "string",\n "description": "The location to get the temperature for, in the format \\"City, Country\\""\n }\n },\n "required": [\n "location"\n ]\n },\n "return": {\n "type": "number",\n "description": "The current temperature at the specified location in the specified units, as a float."\n }\n }\n}\n\nHey, what's the temperature in Paris right now?<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n`, + }, }); describe("End-to-end tests", () => { diff --git a/packages/jinja/test/templates.test.js b/packages/jinja/test/templates.test.js index 7ce91b54b..2246de653 100644 --- a/packages/jinja/test/templates.test.js +++ b/packages/jinja/test/templates.test.js @@ -101,6 +101,7 @@ const TEST_STRINGS = { IS_OPERATOR_3: `|{{ 1 is odd }}|{{ 2 is odd }}|{{ 1 is even }}|{{ 2 is even }}|{{ 2 is number }}|{{ '2' is number }}|{{ 2 is integer }}|{{ '2' is integer }}|`, IS_OPERATOR_4: `|{{ func is callable }}|{{ 2 is callable }}|{{ 1 is iterable }}|{{ 'hello' is iterable }}|`, IS_OPERATOR_5: `|{{ 'a' is lower }}|{{ 'A' is lower }}|{{ 'a' is upper }}|{{ 'A' is upper }}|`, + IS_OPERATOR_6: `|{{ string is mapping }}|{{ number is mapping }}|{{ array is mapping }}|{{ dict is mapping }}|`, // Short-circuit evaluation SHORT_CIRCUIT: `{{ false and raise_exception('This should not be printed') }}`, @@ -2073,6 +2074,33 @@ const TEST_PARSED = { { value: "}}", type: "CloseExpression" }, { value: "|", type: "Text" }, ], + IS_OPERATOR_6: [ + { value: "|", type: "Text" }, + { value: "{{", type: "OpenExpression" }, + { value: "string", type: "Identifier" }, + { value: "is", type: "Is" }, + { value: "mapping", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + { value: "|", type: "Text" }, + { value: "{{", type: "OpenExpression" }, + { value: "number", type: "Identifier" }, + { value: "is", type: "Is" }, + { value: "mapping", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + { value: "|", type: "Text" }, + { value: "{{", type: "OpenExpression" }, + { value: "array", type: "Identifier" }, + { value: "is", type: "Is" }, + { value: "mapping", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + { value: "|", type: "Text" }, + { value: "{{", type: "OpenExpression" }, + { value: "dict", type: "Identifier" }, + { value: "is", type: "Is" }, + { value: "mapping", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + { value: "|", type: "Text" }, + ], // Short-circuit evaluation SHORT_CIRCUIT: [ @@ -2927,6 +2955,12 @@ const TEST_CONTEXT = { func: () => {}, }, IS_OPERATOR_5: {}, + IS_OPERATOR_6: { + string: "hello", + number: 1, + array: [1, 2, 3], + dict: { a: 1 }, + }, // Short-circuit evaluation SHORT_CIRCUIT: {}, @@ -3087,6 +3121,7 @@ const EXPECTED_OUTPUTS = { IS_OPERATOR_3: `|true|false|false|true|true|false|true|false|`, IS_OPERATOR_4: `|true|false|false|true|`, IS_OPERATOR_5: `|true|false|false|true|`, + IS_OPERATOR_6: `|false|false|false|true|`, // Short-circuit evaluation SHORT_CIRCUIT: `false`, From cf671726c043a801004ae3ce8d8be10ae5ceb840 Mon Sep 17 00:00:00 2001 From: "Gilad S." <7817232+giladgd@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:47:10 +0200 Subject: [PATCH 11/97] [jinja] Add support for `rejectattr` filter (#988) I've added support for `rejectattr` in Jinja since I encountered some GGUF models that include a chat template that uses it, like [this one](https://huggingface.co/mradermacher/Mistral-Nemo-Instruct-2407-GGUF) for example. --------- Co-authored-by: Joshua Lochner --- packages/jinja/src/runtime.ts | 15 ++++++----- packages/jinja/test/e2e.test.js | 9 +++++++ packages/jinja/test/templates.test.js | 38 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/packages/jinja/src/runtime.ts b/packages/jinja/src/runtime.ts index 05688f277..474de75f7 100644 --- a/packages/jinja/src/runtime.ts +++ b/packages/jinja/src/runtime.ts @@ -614,12 +614,15 @@ export class Interpreter { if (operand instanceof ArrayValue) { switch (filterName) { - case "selectattr": { + case "selectattr": + case "rejectattr": { + const select = filterName === "selectattr"; + if (operand.value.some((x) => !(x instanceof ObjectValue))) { - throw new Error("`selectattr` can only be applied to array of objects"); + throw new Error(`\`${filterName}\` can only be applied to array of objects`); } if (filter.args.some((x) => x.type !== "StringLiteral")) { - throw new Error("arguments of `selectattr` must be strings"); + throw new Error(`arguments of \`${filterName}\` must be strings`); } const [attr, testName, value] = filter.args.map((x) => this.evaluate(x, environment)) as StringValue[]; @@ -640,10 +643,8 @@ export class Interpreter { // Filter the array using the test function const filtered = (operand.value as ObjectValue[]).filter((item) => { const a = item.value.get(attr.value); - if (a) { - return testFunction(a, value); - } - return false; + const result = a ? testFunction(a, value) : false; + return select ? result : !result; }); return new ArrayValue(filtered); diff --git a/packages/jinja/test/e2e.test.js b/packages/jinja/test/e2e.test.js index 7de154a54..4de0edca0 100644 --- a/packages/jinja/test/e2e.test.js +++ b/packages/jinja/test/e2e.test.js @@ -654,6 +654,15 @@ const TEST_CUSTOM_TEMPLATES = Object.freeze({ }, target: `<|begin_of_text|>You are a function calling AI model. You are provided with function signatures within XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: {"type": "function", "function": {"name": get_stock_fundamentals", "description": "get_stock_fundamentals(symbol: str) -> dict - Get fundamental data for a given stock symbol using yfinance API.\n\n Args:\n symbol(str): The stock symbol.\n Returns:\n A dictionary containing fundamental data.\n\nKeys:\n - 'symbol': The stock symbol.\n - 'company_name': The long name of the company.\n - 'sector': The sector to which the company belongs.\n - 'industry': The industry to which the company belongs.\n - 'market_cap': The market capitalization of the company.\n - 'pe_ratio': The forward price-to-earnings ratio.\n - 'pb_ratio': The price-to-book ratio.\n - 'dividend_yield': The dividend yield.\n - 'eps': The trailing earnings per share.\n - 'beta': The beta value of the stock.\n - '52_week_high': The 52-week high price of the stock.\n - '52_week_low': The 52-week low price of the stock.", "parameters": {"type": "object", "properties": {"symbol": {"type": "string", "description": "The stock symbol."}}, "required": ["symbol"]}} Use the following pydantic model json schema for each tool call you will make: {"properties": {"arguments": {"title": "Arguments", "type": "object"}, "name": {"title": "Name", "type": "string"}}, "required": ["arguments", "name"], "title": "FunctionCall", "type": "object"}\nFor each function call return a json object with function name and arguments within XML tags as follows:\n\n{"arguments": , "name": }\n<|im_end|><|im_start|>user\nFetch the stock fundamentals data for Tesla (TSLA)<|im_end|>\n<|im_start|>assistant\n`, }, + "mistralai/Mistral-Nemo-Instruct-2407": { + chat_template: `{%- if messages[0]["role"] == "system" %}\n {%- set system_message = messages[0]["content"] %}\n {%- set loop_messages = messages[1:] %}\n{%- else %}\n {%- set loop_messages = messages %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n{%- set user_messages = loop_messages | selectattr("role", "equalto", "user") | list %}\n\n{%- for message in loop_messages | rejectattr("role", "equalto", "tool") | rejectattr("role", "equalto", "tool_results") | selectattr("tool_calls", "undefined") %}\n {%- if (message["role"] == "user") != (loop.index0 % 2 == 0) %}\n {{- raise_exception("After the optional system message, conversation roles must alternate user/assistant/user/assistant/...") }}\n {%- endif %}\n{%- endfor %}\n\n{{- bos_token }}\n{%- for message in loop_messages %}\n {%- if message["role"] == "user" %}\n {%- if tools is not none and (message == user_messages[-1]) %}\n {{- "[AVAILABLE_TOOLS][" }}\n {%- for tool in tools %}\n {%- set tool = tool.function %}\n {{- '{"type": "function", "function": {' }}\n {%- for key, val in tool.items() if key != "return" %}\n {%- if val is string %}\n {{- '"' + key + '": "' + val + '"' }}\n {%- else %}\n {{- '"' + key + '": ' + val|tojson }}\n {%- endif %}\n {%- if not loop.last %}\n {{- ", " }}\n {%- endif %}\n {%- endfor %}\n {{- "}}" }}\n {%- if not loop.last %}\n {{- ", " }}\n {%- else %}\n {{- "]" }}\n {%- endif %}\n {%- endfor %}\n {{- "[/AVAILABLE_TOOLS]" }}\n {%- endif %}\n {%- if loop.last and system_message is defined %}\n {{- "[INST]" + system_message + "\\n\\n" + message["content"] + "[/INST]" }}\n {%- else %}\n {{- "[INST]" + message["content"] + "[/INST]" }}\n {%- endif %}\n {%- elif message["role"] == "tool_calls" or message.tool_calls is defined %}\n {%- if message.tool_calls is defined %}\n {%- set tool_calls = message.tool_calls %}\n {%- else %}\n {%- set tool_calls = message.content %}\n {%- endif %}\n {{- "[TOOL_CALLS][" }}\n {%- for tool_call in tool_calls %}\n {%- set out = tool_call.function|tojson %}\n {{- out[:-1] }}\n {%- if not tool_call.id is defined or tool_call.id|length != 9 %}\n {{- raise_exception("Tool call IDs should be alphanumeric strings with length 9!") }}\n {%- endif %}\n {{- ', "id": "' + tool_call.id + '"}' }}\n {%- if not loop.last %}\n {{- ", " }}\n {%- else %}\n {{- "]" + eos_token }}\n {%- endif %}\n {%- endfor %}\n {%- elif message["role"] == "assistant" %}\n {{- message["content"] + eos_token}}\n {%- elif message["role"] == "tool_results" or message["role"] == "tool" %}\n {%- if message.content is defined and message.content.content is defined %}\n {%- set content = message.content.content %}\n {%- else %}\n {%- set content = message.content %}\n {%- endif %}\n {{- '[TOOL_RESULTS]{"content": ' + content|string + ", " }}\n {%- if not message.tool_call_id is defined or message.tool_call_id|length != 9 %}\n {{- raise_exception("Tool call IDs should be alphanumeric strings with length 9!") }}\n {%- endif %}\n {{- '"call_id": "' + message.tool_call_id + '"}[/TOOL_RESULTS]' }}\n {%- else %}\n {{- raise_exception("Only user and assistant roles are supported, with the exception of an initial optional system message!") }}\n {%- endif %}\n{%- endfor %}\n`, + data: { + messages: EXAMPLE_CHAT, + bos_token: "", + eos_token: "" + }, + target: `[INST]Hello, how are you?[/INST]I'm doing great. How can I help you today?[INST]I'd like to show off how chat templating works![/INST]`, + }, "meta-llama/Llama-3.1-8B-Instruct": { chat_template: `{{- bos_token }}\n{%- if custom_tools is defined %}\n {%- set tools = custom_tools %}\n{%- endif %}\n{%- if not tools_in_user_message is defined %}\n {%- set tools_in_user_message = true %}\n{%- endif %}\n{%- if not date_string is defined %}\n {%- set date_string = "26 Jul 2024" %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n\n{#- This block extracts the system message, so we can slot it into the right place. #}\n{%- if messages[0]['role'] == 'system' %}\n {%- set system_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n{%- else %}\n {%- set system_message = "" %}\n{%- endif %}\n\n{#- System message + builtin tools #}\n{{- "<|start_header_id|>system<|end_header_id|>\\n\\n" }}\n{%- if builtin_tools is defined or tools is not none %}\n {{- "Environment: ipython\\n" }}\n{%- endif %}\n{%- if builtin_tools is defined %}\n {{- "Tools: " + builtin_tools | reject('equalto', 'code_interpreter') | join(", ") + "\\n\\n"}}\n{%- endif %}\n{{- "Cutting Knowledge Date: December 2023\\n" }}\n{{- "Today Date: " + date_string + "\\n\\n" }}\n{%- if tools is not none and not tools_in_user_message %}\n {{- "You have access to the following functions. To call a function, please respond with JSON for a function call." }}\n {{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}\n {{- "Do not use variables.\\n\\n" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- "\\n\\n" }}\n {%- endfor %}\n{%- endif %}\n{{- system_message }}\n{{- "<|eot_id|>" }}\n\n{#- Custom tools are passed in a user message with some extra guidance #}\n{%- if tools_in_user_message and not tools is none %}\n {#- Extract the first user message so we can plug it in here #}\n {%- if messages | length != 0 %}\n {%- set first_user_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n {%- else %}\n {{- raise_exception("Cannot put tools in the first user message when there's no first user message!") }}\n{%- endif %}\n {{- '<|start_header_id|>user<|end_header_id|>\\n\\n' -}}\n {{- "Given the following functions, please respond with a JSON for a function call " }}\n {{- "with its proper arguments that best answers the given prompt.\\n\\n" }}\n {{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}\n {{- "Do not use variables.\\n\\n" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- "\\n\\n" }}\n {%- endfor %}\n {{- first_user_message + "<|eot_id|>"}}\n{%- endif %}\n\n{%- for message in messages %}\n {%- if not (message.role == 'ipython' or message.role == 'tool' or 'tool_calls' in message) %}\n {{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\\n\\n'+ message['content'] | trim + '<|eot_id|>' }}\n {%- elif 'tool_calls' in message %}\n {%- if not message.tool_calls|length == 1 %}\n {{- raise_exception("This model only supports single tool-calls at once!") }}\n {%- endif %}\n {%- set tool_call = message.tool_calls[0].function %}\n {%- if builtin_tools is defined and tool_call.name in builtin_tools %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- "<|python_tag|>" + tool_call.name + ".call(" }}\n {%- for arg_name, arg_val in tool_call.arguments | items %}\n {{- arg_name + '="' + arg_val + '"' }}\n {%- if not loop.last %}\n {{- ", " }}\n {%- endif %}\n {%- endfor %}\n {{- ")" }}\n {%- else %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- '{"name": "' + tool_call.name + '", ' }}\n {{- '"parameters": ' }}\n {{- tool_call.arguments | tojson }}\n {{- "}" }}\n {%- endif %}\n {%- if builtin_tools is defined %}\n {#- This means we're in ipython mode #}\n {{- "<|eom_id|>" }}\n {%- else %}\n {{- "<|eot_id|>" }}\n {%- endif %}\n {%- elif message.role == "tool" or message.role == "ipython" %}\n {{- "<|start_header_id|>ipython<|end_header_id|>\\n\\n" }}\n {%- if message.content is mapping or message.content is iterable %}\n {{- message.content | tojson }}\n {%- else %}\n {{- message.content }}\n {%- endif %}\n {{- "<|eot_id|>" }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' }}\n{%- endif %}\n`, data: { diff --git a/packages/jinja/test/templates.test.js b/packages/jinja/test/templates.test.js index 2246de653..0a5f9130f 100644 --- a/packages/jinja/test/templates.test.js +++ b/packages/jinja/test/templates.test.js @@ -87,6 +87,8 @@ const TEST_STRINGS = { FILTER_OPERATOR_8: `{{ obj | tojson(indent=2) }}`, FILTER_OPERATOR_9: `{{ data | map(attribute='val') | list | tojson }}`, FILTER_OPERATOR_10: `|{{ " 1 \n 2 \n 3 \n\n " | indent }}|{{ " 1 \n 2 \n 3 \n\n " | indent(2) }}|{{ " 1 \n 2 \n 3 \n\n " | indent(first=True) }}|{{ " 1 \n 2 \n 3 \n\n " | indent(blank=True) }}|{{ " 1 \n 2 \n 3 \n\n " | indent(4, first=True) }}|`, + FILTER_OPERATOR_11: `{{ items | rejectattr('key') | length }}`, + FILTER_OPERATOR_12: `{{ messages | rejectattr('role', 'equalto', 'system') | length }}`, // Logical operators between non-Booleans BOOLEAN_NUMERICAL: `|{{ 1 and 2 }}|{{ 1 and 0 }}|{{ 0 and 1 }}|{{ 0 and 0 }}|{{ 1 or 2 }}|{{ 1 or 0 }}|{{ 0 or 1 }}|{{ 0 or 0 }}|{{ not 1 }}|{{ not 0 }}|`, @@ -1625,6 +1627,34 @@ const TEST_PARSED = { { value: "}}", type: "CloseExpression" }, { value: "|", type: "Text" }, ], + FILTER_OPERATOR_11: [ + { value: "{{", type: "OpenExpression" }, + { value: "items", type: "Identifier" }, + { value: "|", type: "Pipe" }, + { value: "rejectattr", type: "Identifier" }, + { value: "(", type: "OpenParen" }, + { value: "key", type: "StringLiteral" }, + { value: ")", type: "CloseParen" }, + { value: "|", type: "Pipe" }, + { value: "length", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + ], + FILTER_OPERATOR_12: [ + { value: "{{", type: "OpenExpression" }, + { value: "messages", type: "Identifier" }, + { value: "|", type: "Pipe" }, + { value: "rejectattr", type: "Identifier" }, + { value: "(", type: "OpenParen" }, + { value: "role", type: "StringLiteral" }, + { value: ",", type: "Comma" }, + { value: "equalto", type: "StringLiteral" }, + { value: ",", type: "Comma" }, + { value: "system", type: "StringLiteral" }, + { value: ")", type: "CloseParen" }, + { value: "|", type: "Pipe" }, + { value: "length", type: "Identifier" }, + { value: "}}", type: "CloseExpression" }, + ], // Logical operators between non-Booleans BOOLEAN_NUMERICAL: [ @@ -2937,6 +2967,12 @@ const TEST_CONTEXT = { data: [{ val: 1 }, { val: 2 }, { val: 3 }], }, FILTER_OPERATOR_10: {}, + FILTER_OPERATOR_11: { + items: [{ key: "a" }, { key: 0 }, { key: 1 }, {}, { key: false }], + }, + FILTER_OPERATOR_12: { + messages: [{ role: "system" }, { role: "user" }, { role: "assistant" }], + }, // Logical operators between non-Booleans BOOLEAN_NUMERICAL: {}, @@ -3107,6 +3143,8 @@ const EXPECTED_OUTPUTS = { FILTER_OPERATOR_8: `{\n "a": [\n 1,\n 2,\n 3\n ],\n "b": 1,\n "c": {\n "d": 2,\n "e": {\n "f": 3,\n "g": {\n "h": 4,\n "i": [\n 1,\n 2,\n 3\n ]\n }\n }\n }\n}`, FILTER_OPERATOR_9: `[1, 2, 3]`, FILTER_OPERATOR_10: `| 1 \n 2 \n 3 \n\n | 1 \n 2 \n 3 \n\n | 1 \n 2 \n 3 \n\n | 1 \n 2 \n 3 \n \n | 1 \n 2 \n 3 \n\n |`, + FILTER_OPERATOR_11: `3`, + FILTER_OPERATOR_12: `2`, // Logical operators between non-Booleans BOOLEAN_NUMERICAL: `|2|0|0|0|1|1|1|0|false|true|`, From fdde9c820f04115cacf414acc7cf49154a6be81d Mon Sep 17 00:00:00 2001 From: Joshua Lochner Date: Wed, 30 Oct 2024 12:56:17 +0200 Subject: [PATCH 12/97] Fix formatting & linting (#997) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason, CI was green before merging #995, but missed the formatting and linting step. This PR should fix it 👍 --- packages/jinja/pnpm-lock.yaml | 379 ++++++++++++++++++++------------ packages/jinja/test/e2e.test.js | 2 +- 2 files changed, 237 insertions(+), 144 deletions(-) diff --git a/packages/jinja/pnpm-lock.yaml b/packages/jinja/pnpm-lock.yaml index a6ecf2e33..11e24490c 100644 --- a/packages/jinja/pnpm-lock.yaml +++ b/packages/jinja/pnpm-lock.yaml @@ -16,9 +16,9 @@ devDependencies: version: 5.3.2 packages: - /@emnapi/runtime@1.3.1: - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + resolution: + { integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== } requiresBuild: true dependencies: tslib: 2.8.0 @@ -26,12 +26,14 @@ packages: optional: true /@huggingface/jinja@0.3.1: - resolution: {integrity: sha512-SbcBWUKDQ76lzlVYOloscUk0SJjuL1LcbZsfQv/Bxxc7dwJMYuS+DAQ+HhVw6ZkTFXArejaX5HQRuCuleYwYdA==} - engines: {node: ">=18"} + resolution: + { integrity: sha512-SbcBWUKDQ76lzlVYOloscUk0SJjuL1LcbZsfQv/Bxxc7dwJMYuS+DAQ+HhVw6ZkTFXArejaX5HQRuCuleYwYdA== } + engines: { node: ">=18" } dev: true /@huggingface/transformers@3.0.0: - resolution: {integrity: sha512-OWIPnTijAw4DQ+IFHBOrej2SDdYyykYlTtpTLCEt5MZq/e9Cb65RS2YVhdGcgbaW/6JAL3i8ZA5UhDeWGm4iRQ==} + resolution: + { integrity: sha512-OWIPnTijAw4DQ+IFHBOrej2SDdYyykYlTtpTLCEt5MZq/e9Cb65RS2YVhdGcgbaW/6JAL3i8ZA5UhDeWGm4iRQ== } dependencies: "@huggingface/jinja": 0.3.1 onnxruntime-node: 1.19.2 @@ -40,8 +42,9 @@ packages: dev: true /@img/sharp-darwin-arm64@0.33.5: - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [darwin] requiresBuild: true @@ -51,8 +54,9 @@ packages: optional: true /@img/sharp-darwin-x64@0.33.5: - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [darwin] requiresBuild: true @@ -62,7 +66,8 @@ packages: optional: true /@img/sharp-libvips-darwin-arm64@1.0.4: - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + resolution: + { integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== } cpu: [arm64] os: [darwin] requiresBuild: true @@ -70,7 +75,8 @@ packages: optional: true /@img/sharp-libvips-darwin-x64@1.0.4: - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + resolution: + { integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== } cpu: [x64] os: [darwin] requiresBuild: true @@ -78,7 +84,8 @@ packages: optional: true /@img/sharp-libvips-linux-arm64@1.0.4: - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + resolution: + { integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== } cpu: [arm64] os: [linux] requiresBuild: true @@ -86,7 +93,8 @@ packages: optional: true /@img/sharp-libvips-linux-arm@1.0.5: - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + resolution: + { integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== } cpu: [arm] os: [linux] requiresBuild: true @@ -94,7 +102,8 @@ packages: optional: true /@img/sharp-libvips-linux-s390x@1.0.4: - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + resolution: + { integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== } cpu: [s390x] os: [linux] requiresBuild: true @@ -102,7 +111,8 @@ packages: optional: true /@img/sharp-libvips-linux-x64@1.0.4: - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + resolution: + { integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== } cpu: [x64] os: [linux] requiresBuild: true @@ -110,7 +120,8 @@ packages: optional: true /@img/sharp-libvips-linuxmusl-arm64@1.0.4: - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + resolution: + { integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== } cpu: [arm64] os: [linux] requiresBuild: true @@ -118,7 +129,8 @@ packages: optional: true /@img/sharp-libvips-linuxmusl-x64@1.0.4: - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + resolution: + { integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== } cpu: [x64] os: [linux] requiresBuild: true @@ -126,8 +138,9 @@ packages: optional: true /@img/sharp-linux-arm64@0.33.5: - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] requiresBuild: true @@ -137,8 +150,9 @@ packages: optional: true /@img/sharp-linux-arm@0.33.5: - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm] os: [linux] requiresBuild: true @@ -148,8 +162,9 @@ packages: optional: true /@img/sharp-linux-s390x@0.33.5: - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [s390x] os: [linux] requiresBuild: true @@ -159,8 +174,9 @@ packages: optional: true /@img/sharp-linux-x64@0.33.5: - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] requiresBuild: true @@ -170,8 +186,9 @@ packages: optional: true /@img/sharp-linuxmusl-arm64@0.33.5: - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] requiresBuild: true @@ -181,8 +198,9 @@ packages: optional: true /@img/sharp-linuxmusl-x64@0.33.5: - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] requiresBuild: true @@ -192,8 +210,9 @@ packages: optional: true /@img/sharp-wasm32@0.33.5: - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [wasm32] requiresBuild: true dependencies: @@ -202,8 +221,9 @@ packages: optional: true /@img/sharp-win32-ia32@0.33.5: - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [ia32] os: [win32] requiresBuild: true @@ -211,8 +231,9 @@ packages: optional: true /@img/sharp-win32-x64@0.33.5: - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [win32] requiresBuild: true @@ -220,8 +241,9 @@ packages: optional: true /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== } + engines: { node: ">=12" } dependencies: string-width: 5.1.2 string-width-cjs: /string-width@4.2.3 @@ -232,134 +254,159 @@ packages: dev: true /@isaacs/fs-minipass@4.0.1: - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: ">=18.0.0"} + resolution: + { integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== } + engines: { node: ">=18.0.0" } dependencies: minipass: 7.1.2 dev: true /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: ">=14"} + resolution: + { integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== } + engines: { node: ">=14" } requiresBuild: true dev: true optional: true /@protobufjs/aspromise@1.1.2: - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + resolution: + { integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== } dev: true /@protobufjs/base64@1.1.2: - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + resolution: + { integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== } dev: true /@protobufjs/codegen@2.0.4: - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + resolution: + { integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== } dev: true /@protobufjs/eventemitter@1.1.0: - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + resolution: + { integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== } dev: true /@protobufjs/fetch@1.1.0: - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + resolution: + { integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== } dependencies: "@protobufjs/aspromise": 1.1.2 "@protobufjs/inquire": 1.1.0 dev: true /@protobufjs/float@1.0.2: - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + resolution: + { integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== } dev: true /@protobufjs/inquire@1.1.0: - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + resolution: + { integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== } dev: true /@protobufjs/path@1.1.2: - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + resolution: + { integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== } dev: true /@protobufjs/pool@1.1.0: - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + resolution: + { integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== } dev: true /@protobufjs/utf8@1.1.0: - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + resolution: + { integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== } dev: true /@types/node@20.9.4: - resolution: {integrity: sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==} + resolution: + { integrity: sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA== } dependencies: undici-types: 5.26.5 dev: true /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== } + engines: { node: ">=8" } dev: true /ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== } + engines: { node: ">=12" } dev: true /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== } + engines: { node: ">=8" } dependencies: color-convert: 2.0.1 dev: true /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== } + engines: { node: ">=12" } dev: true /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + { integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== } dev: true /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + resolution: + { integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== } dependencies: balanced-match: 1.0.2 dev: true /chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: ">=18"} + resolution: + { integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== } + engines: { node: ">=18" } dev: true /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: ">=7.0.0"} + resolution: + { integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== } + engines: { node: ">=7.0.0" } dependencies: color-name: 1.1.4 dev: true /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + resolution: + { integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== } dev: true /color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + resolution: + { integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== } dependencies: color-name: 1.1.4 simple-swizzle: 0.2.2 dev: true /color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: ">=12.5.0"} + resolution: + { integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== } + engines: { node: ">=12.5.0" } dependencies: color-convert: 2.0.1 color-string: 1.9.1 dev: true /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: ">= 8"} + resolution: + { integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== } + engines: { node: ">= 8" } dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -367,36 +414,43 @@ packages: dev: true /detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== } + engines: { node: ">=8" } dev: true /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + resolution: + { integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== } dev: true /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + resolution: + { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== } dev: true /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + resolution: + { integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== } dev: true /flatbuffers@1.12.0: - resolution: {integrity: sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==} + resolution: + { integrity: sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ== } dev: true /foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} - engines: {node: ">=14"} + resolution: + { integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== } + engines: { node: ">=14" } dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 dev: true /glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + resolution: + { integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== } hasBin: true dependencies: foreground-child: 3.3.0 @@ -408,24 +462,29 @@ packages: dev: true /guid-typescript@1.0.9: - resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} + resolution: + { integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ== } dev: true /is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + resolution: + { integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== } dev: true /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== } + engines: { node: ">=8" } dev: true /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolution: + { integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== } dev: true /jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + resolution: + { integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== } dependencies: "@isaacs/cliui": 8.0.2 optionalDependencies: @@ -433,49 +492,58 @@ packages: dev: true /long@5.2.3: - resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + resolution: + { integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== } dev: true /lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + resolution: + { integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== } dev: true /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: ">=16 || 14 >=14.17"} + resolution: + { integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== } + engines: { node: ">=16 || 14 >=14.17" } dependencies: brace-expansion: 2.0.1 dev: true /minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: ">=16 || 14 >=14.17"} + resolution: + { integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== } + engines: { node: ">=16 || 14 >=14.17" } dev: true /minizlib@3.0.1: - resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} - engines: {node: ">= 18"} + resolution: + { integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== } + engines: { node: ">= 18" } dependencies: minipass: 7.1.2 rimraf: 5.0.10 dev: true /mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: ">=10"} + resolution: + { integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== } + engines: { node: ">=10" } hasBin: true dev: true /onnxruntime-common@1.19.2: - resolution: {integrity: sha512-a4R7wYEVFbZBlp0BfhpbFWqe4opCor3KM+5Wm22Az3NGDcQMiU2hfG/0MfnBs+1ZrlSGmlgWeMcXQkDk1UFb8Q==} + resolution: + { integrity: sha512-a4R7wYEVFbZBlp0BfhpbFWqe4opCor3KM+5Wm22Az3NGDcQMiU2hfG/0MfnBs+1ZrlSGmlgWeMcXQkDk1UFb8Q== } dev: true /onnxruntime-common@1.20.0-dev.20241016-2b8fc5529b: - resolution: {integrity: sha512-KZK8b6zCYGZFjd4ANze0pqBnqnFTS3GIVeclQpa2qseDpXrCQJfkWBixRcrZShNhm3LpFOZ8qJYFC5/qsJK9WQ==} + resolution: + { integrity: sha512-KZK8b6zCYGZFjd4ANze0pqBnqnFTS3GIVeclQpa2qseDpXrCQJfkWBixRcrZShNhm3LpFOZ8qJYFC5/qsJK9WQ== } dev: true /onnxruntime-node@1.19.2: - resolution: {integrity: sha512-9eHMP/HKbbeUcqte1JYzaaRC8JPn7ojWeCeoyShO86TOR97OCyIyAIOGX3V95ErjslVhJRXY8Em/caIUc0hm1Q==} + resolution: + { integrity: sha512-9eHMP/HKbbeUcqte1JYzaaRC8JPn7ojWeCeoyShO86TOR97OCyIyAIOGX3V95ErjslVhJRXY8Em/caIUc0hm1Q== } os: [win32, darwin, linux] requiresBuild: true dependencies: @@ -484,7 +552,8 @@ packages: dev: true /onnxruntime-web@1.20.0-dev.20241016-2b8fc5529b: - resolution: {integrity: sha512-1XovqtgqeEFtupuyzdDQo7Tqj4GRyNHzOoXjapCEo4rfH3JrXok5VtqucWfRXHPsOI5qoNxMQ9VE+drDIp6woQ==} + resolution: + { integrity: sha512-1XovqtgqeEFtupuyzdDQo7Tqj4GRyNHzOoXjapCEo4rfH3JrXok5VtqucWfRXHPsOI5qoNxMQ9VE+drDIp6woQ== } dependencies: flatbuffers: 1.12.0 guid-typescript: 1.0.9 @@ -495,29 +564,34 @@ packages: dev: true /package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + resolution: + { integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== } dev: true /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== } + engines: { node: ">=8" } dev: true /path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: ">=16 || 14 >=14.18"} + resolution: + { integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== } + engines: { node: ">=16 || 14 >=14.18" } dependencies: lru-cache: 10.4.3 minipass: 7.1.2 dev: true /platform@1.3.6: - resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + resolution: + { integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== } dev: true /protobufjs@7.4.0: - resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==} - engines: {node: ">=12.0.0"} + resolution: + { integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== } + engines: { node: ">=12.0.0" } requiresBuild: true dependencies: "@protobufjs/aspromise": 1.1.2 @@ -535,21 +609,24 @@ packages: dev: true /rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + resolution: + { integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== } hasBin: true dependencies: glob: 10.4.5 dev: true /semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: ">=10"} + resolution: + { integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== } + engines: { node: ">=10" } hasBin: true dev: true /sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw== } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } requiresBuild: true dependencies: color: 4.2.3 @@ -578,31 +655,36 @@ packages: dev: true /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== } + engines: { node: ">=8" } dependencies: shebang-regex: 3.0.0 dev: true /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== } + engines: { node: ">=8" } dev: true /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: ">=14"} + resolution: + { integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== } + engines: { node: ">=14" } dev: true /simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + resolution: + { integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== } dependencies: is-arrayish: 0.3.2 dev: true /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== } + engines: { node: ">=8" } dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 @@ -610,8 +692,9 @@ packages: dev: true /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== } + engines: { node: ">=12" } dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 @@ -619,22 +702,25 @@ packages: dev: true /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: ">=8"} + resolution: + { integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== } + engines: { node: ">=8" } dependencies: ansi-regex: 5.0.1 dev: true /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== } + engines: { node: ">=12" } dependencies: ansi-regex: 6.1.0 dev: true /tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} - engines: {node: ">=18"} + resolution: + { integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== } + engines: { node: ">=18" } dependencies: "@isaacs/fs-minipass": 4.0.1 chownr: 3.0.0 @@ -645,32 +731,37 @@ packages: dev: true /tslib@2.8.0: - resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + resolution: + { integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== } requiresBuild: true dev: true optional: true /typescript@5.3.2: - resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} - engines: {node: ">=14.17"} + resolution: + { integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== } + engines: { node: ">=14.17" } hasBin: true dev: true /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + resolution: + { integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== } dev: true /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: ">= 8"} + resolution: + { integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== } + engines: { node: ">= 8" } hasBin: true dependencies: isexe: 2.0.0 dev: true /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: ">=10"} + resolution: + { integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== } + engines: { node: ">=10" } dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 @@ -678,8 +769,9 @@ packages: dev: true /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: ">=12"} + resolution: + { integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== } + engines: { node: ">=12" } dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 @@ -687,6 +779,7 @@ packages: dev: true /yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: ">=18"} + resolution: + { integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== } + engines: { node: ">=18" } dev: true diff --git a/packages/jinja/test/e2e.test.js b/packages/jinja/test/e2e.test.js index 4de0edca0..833a1a854 100644 --- a/packages/jinja/test/e2e.test.js +++ b/packages/jinja/test/e2e.test.js @@ -659,7 +659,7 @@ const TEST_CUSTOM_TEMPLATES = Object.freeze({ data: { messages: EXAMPLE_CHAT, bos_token: "", - eos_token: "" + eos_token: "", }, target: `[INST]Hello, how are you?[/INST]I'm doing great. How can I help you today?[INST]I'd like to show off how chat templating works![/INST]`, }, From a965b74fe67ecf58e49049e35a7517756e330804 Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 30 Oct 2024 11:01:20 +0000 Subject: [PATCH 13/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/jinja=200.3.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/jinja/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jinja/package.json b/packages/jinja/package.json index e62dcd802..b70794ab1 100644 --- a/packages/jinja/package.json +++ b/packages/jinja/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/jinja", "packageManager": "pnpm@8.10.5", - "version": "0.3.1", + "version": "0.3.2", "description": "A minimalistic JavaScript implementation of the Jinja templating engine, specifically designed for parsing and rendering ML chat templates.", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From c565b6b67b6568b6933f059536823800469ac169 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Wed, 30 Oct 2024 12:47:44 +0100 Subject: [PATCH 14/97] Fix modelInfo typing (#998) Fix #996 --- packages/hub/src/lib/model-info.spec.ts | 2 ++ packages/hub/src/lib/model-info.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/hub/src/lib/model-info.spec.ts b/packages/hub/src/lib/model-info.spec.ts index cdbad71c1..81e6f8246 100644 --- a/packages/hub/src/lib/model-info.spec.ts +++ b/packages/hub/src/lib/model-info.spec.ts @@ -5,10 +5,12 @@ describe("modelInfo", () => { it("should return the model info", async () => { const info = await modelInfo({ name: "openai-community/gpt2", + additionalFields: ["author"], }); expect(info).toEqual({ id: "621ffdc036468d709f17434d", downloads: expect.any(Number), + author: "openai-community", gated: false, name: "openai-community/gpt2", updatedAt: expect.any(Date), diff --git a/packages/hub/src/lib/model-info.ts b/packages/hub/src/lib/model-info.ts index 2744905c0..02f41d717 100644 --- a/packages/hub/src/lib/model-info.ts +++ b/packages/hub/src/lib/model-info.ts @@ -7,7 +7,7 @@ import { pick } from "../utils/pick"; import { MODEL_EXPAND_KEYS, type MODEL_EXPANDABLE_KEYS, type ModelEntry } from "./list-models"; export async function modelInfo< - const T extends Exclude<(typeof MODEL_EXPANDABLE_KEYS)[number], (typeof MODEL_EXPANDABLE_KEYS)[number]> = never, + const T extends Exclude<(typeof MODEL_EXPANDABLE_KEYS)[number], (typeof MODEL_EXPAND_KEYS)[number]> = never, >( params: { name: string; From 8a2079bf642e4b2c5ce29b80dc1f5e95896b27e5 Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 30 Oct 2024 11:48:31 +0000 Subject: [PATCH 15/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/hub=200.18.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- packages/hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc0c9a39e..a3a11ae57 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or ```html ``` diff --git a/packages/hub/package.json b/packages/hub/package.json index 8ad93a2b5..8e5807f71 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/hub", "packageManager": "pnpm@8.10.5", - "version": "0.18.2", + "version": "0.18.3", "description": "Utilities to interact with the Hugging Face hub", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From d623bbd6f4b419d1a9ab61006a23dde1daf52b41 Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:07:44 +0100 Subject: [PATCH 16/97] feat(hub): adding revision property to modelInfo, datasetInfo, spaceInfo (#999) When getting modelInfo, datasetInfo, spaceInfo, we might need to get the details for a specific revision. This PR adds an optional `revision` property to those methods --- packages/hub/src/lib/dataset-info.spec.ts | 37 +++++++++++++++++++++++ packages/hub/src/lib/dataset-info.ts | 6 +++- packages/hub/src/lib/model-info.spec.ts | 37 +++++++++++++++++++++++ packages/hub/src/lib/model-info.ts | 6 +++- packages/hub/src/lib/space-info.spec.ts | 35 +++++++++++++++++++++ packages/hub/src/lib/space-info.ts | 6 +++- 6 files changed, 124 insertions(+), 3 deletions(-) diff --git a/packages/hub/src/lib/dataset-info.spec.ts b/packages/hub/src/lib/dataset-info.spec.ts index 8f944de6d..982bdcf40 100644 --- a/packages/hub/src/lib/dataset-info.spec.ts +++ b/packages/hub/src/lib/dataset-info.spec.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "vitest"; import { datasetInfo } from "./dataset-info"; +import type { DatasetEntry } from "./list-datasets"; +import type { ApiDatasetInfo } from "../types/api/api-dataset"; describe("datasetInfo", () => { it("should return the dataset info", async () => { @@ -16,4 +18,39 @@ describe("datasetInfo", () => { private: false, }); }); + + it("should return the dataset info with author", async () => { + const info: DatasetEntry & Pick = await datasetInfo({ + name: "nyu-mll/glue", + additionalFields: ['author'], + }); + expect(info).toEqual({ + id: "621ffdd236468d709f181e3f", + downloads: expect.any(Number), + gated: false, + name: "nyu-mll/glue", + updatedAt: expect.any(Date), + likes: expect.any(Number), + private: false, + author: 'nyu-mll' + }); + }); + + it("should return the dataset info for a specific revision", async () => { + const info: DatasetEntry & Pick = await datasetInfo({ + name: "nyu-mll/glue", + revision: "cb2099c76426ff97da7aa591cbd317d91fb5fcb7", + additionalFields: ["sha"], + }); + expect(info).toEqual({ + id: "621ffdd236468d709f181e3f", + downloads: expect.any(Number), + gated: false, + name: "nyu-mll/glue", + updatedAt: expect.any(Date), + likes: expect.any(Number), + private: false, + sha: 'cb2099c76426ff97da7aa591cbd317d91fb5fcb7' + }); + }); }); diff --git a/packages/hub/src/lib/dataset-info.ts b/packages/hub/src/lib/dataset-info.ts index 42f479d04..bb62df7f8 100644 --- a/packages/hub/src/lib/dataset-info.ts +++ b/packages/hub/src/lib/dataset-info.ts @@ -13,6 +13,10 @@ export async function datasetInfo< name: string; hubUrl?: string; additionalFields?: T[]; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + */ + revision?: string; /** * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ @@ -27,7 +31,7 @@ export async function datasetInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/datasets/${params.name}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/datasets/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), diff --git a/packages/hub/src/lib/model-info.spec.ts b/packages/hub/src/lib/model-info.spec.ts index 81e6f8246..3886f3039 100644 --- a/packages/hub/src/lib/model-info.spec.ts +++ b/packages/hub/src/lib/model-info.spec.ts @@ -1,10 +1,28 @@ import { describe, expect, it } from "vitest"; import { modelInfo } from "./model-info"; +import type { ModelEntry } from "./list-models"; +import type { ApiModelInfo } from "../types/api/api-model"; describe("modelInfo", () => { it("should return the model info", async () => { const info = await modelInfo({ name: "openai-community/gpt2", + }); + expect(info).toEqual({ + id: "621ffdc036468d709f17434d", + downloads: expect.any(Number), + gated: false, + name: "openai-community/gpt2", + updatedAt: expect.any(Date), + likes: expect.any(Number), + task: "text-generation", + private: false, + }); + }); + + it("should return the model info with author", async () => { + const info: ModelEntry & Pick = await modelInfo({ + name: "openai-community/gpt2", additionalFields: ["author"], }); expect(info).toEqual({ @@ -19,4 +37,23 @@ describe("modelInfo", () => { private: false, }); }); + + it("should return the model info for a specific revision", async () => { + const info: ModelEntry & Pick = await modelInfo({ + name: "openai-community/gpt2", + additionalFields: ["sha"], + revision: 'f27b190eeac4c2302d24068eabf5e9d6044389ae', + }); + expect(info).toEqual({ + id: "621ffdc036468d709f17434d", + downloads: expect.any(Number), + gated: false, + name: "openai-community/gpt2", + updatedAt: expect.any(Date), + likes: expect.any(Number), + task: "text-generation", + private: false, + sha: "f27b190eeac4c2302d24068eabf5e9d6044389ae", + }); + }); }); diff --git a/packages/hub/src/lib/model-info.ts b/packages/hub/src/lib/model-info.ts index 02f41d717..828322e67 100644 --- a/packages/hub/src/lib/model-info.ts +++ b/packages/hub/src/lib/model-info.ts @@ -13,6 +13,10 @@ export async function modelInfo< name: string; hubUrl?: string; additionalFields?: T[]; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + */ + revision?: string; /** * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ @@ -27,7 +31,7 @@ export async function modelInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/models/${params.name}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/models/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), diff --git a/packages/hub/src/lib/space-info.spec.ts b/packages/hub/src/lib/space-info.spec.ts index 1974a04c4..aafa9b88f 100644 --- a/packages/hub/src/lib/space-info.spec.ts +++ b/packages/hub/src/lib/space-info.spec.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "vitest"; import { spaceInfo } from "./space-info"; +import type { SpaceEntry } from "./list-spaces"; +import type { ApiSpaceInfo } from "../types/api/api-space"; describe("spaceInfo", () => { it("should return the space info", async () => { @@ -15,4 +17,37 @@ describe("spaceInfo", () => { sdk: "static", }); }); + + it("should return the space info with author", async () => { + const info: SpaceEntry & Pick = await spaceInfo({ + name: "huggingfacejs/client-side-oauth", + additionalFields: ['author'], + }); + expect(info).toEqual({ + id: "659835e689010f9c7aed608d", + name: "huggingfacejs/client-side-oauth", + updatedAt: expect.any(Date), + likes: expect.any(Number), + private: false, + sdk: "static", + author: 'huggingfacejs', + }); + }); + + it("should return the space info for a given revision", async () => { + const info: SpaceEntry & Pick = await spaceInfo({ + name: "huggingfacejs/client-side-oauth", + additionalFields: ['sha'], + revision: 'e410a9ff348e6bed393b847711e793282d7c672e' + }); + expect(info).toEqual({ + id: "659835e689010f9c7aed608d", + name: "huggingfacejs/client-side-oauth", + updatedAt: expect.any(Date), + likes: expect.any(Number), + private: false, + sdk: "static", + sha: 'e410a9ff348e6bed393b847711e793282d7c672e', + }); + }); }); diff --git a/packages/hub/src/lib/space-info.ts b/packages/hub/src/lib/space-info.ts index a1b5516a6..fcbfee60d 100644 --- a/packages/hub/src/lib/space-info.ts +++ b/packages/hub/src/lib/space-info.ts @@ -14,6 +14,10 @@ export async function spaceInfo< name: string; hubUrl?: string; additionalFields?: T[]; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + */ + revision?: string; /** * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ @@ -28,7 +32,7 @@ export async function spaceInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/spaces/${params.name}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/spaces/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), From b0225c49c4e2e8225d284f5ed68c8ffbdb868315 Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 30 Oct 2024 13:08:40 +0000 Subject: [PATCH 17/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/hub=200.19.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- packages/hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3a11ae57..2d9e5f3dc 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or ```html ``` diff --git a/packages/hub/package.json b/packages/hub/package.json index 8e5807f71..e72409216 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/hub", "packageManager": "pnpm@8.10.5", - "version": "0.18.3", + "version": "0.19.0", "description": "Utilities to interact with the Hugging Face hub", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 3881d1224d2c7296f8acea5cf0f060f9d822bfe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20G=C3=B6rner?= Date: Wed, 30 Oct 2024 14:58:51 +0100 Subject: [PATCH 18/97] initial keras-hub support (#986) Initial support for Keras-hub: - generic snippet for loading models - library definition with metadata This PR also adds "keras-hub" as one of the "filtered" i.e. top libraries and removes "tf-keras" from the list. This affects the default library filters in "Models" and the library completions in the Model details edition form. --------- Co-authored-by: Pedro Cuenca Co-authored-by: Lucain Co-authored-by: Julien Chaumond Co-authored-by: vb --- .../tasks/src/model-libraries-snippets.ts | 23 +++++++++++++++---- packages/tasks/src/model-libraries.ts | 13 ++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index 0be11f247..fc4280533 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -364,9 +364,9 @@ model = GLiNER.from_pretrained("${model.id}")`, ]; export const keras = (model: ModelData): string[] => [ - `# Available backend options are: "jax", "tensorflow", "torch". + `# Available backend options are: "jax", "torch", "tensorflow". import os -os.environ["KERAS_BACKEND"] = "tensorflow" +os.environ["KERAS_BACKEND"] = "jax" import keras @@ -375,9 +375,9 @@ model = keras.saving.load_model("hf://${model.id}") ]; export const keras_nlp = (model: ModelData): string[] => [ - `# Available backend options are: "jax", "tensorflow", "torch". + `# Available backend options are: "jax", "torch", "tensorflow". import os -os.environ["KERAS_BACKEND"] = "tensorflow" +os.environ["KERAS_BACKEND"] = "jax" import keras_nlp @@ -386,6 +386,21 @@ backbone = keras_nlp.models.Backbone.from_preset("hf://${model.id}") `, ]; +export const keras_hub = (model: ModelData): string[] => [ + `# Available backend options are: "jax", "torch", "tensorflow". +import os +os.environ["KERAS_BACKEND"] = "jax" + +import keras_hub + +# Load a task-specific model (*replace CausalLM with your task*) +model = keras_hub.models.CausalLM.from_preset("hf://${model.id}", dtype="bfloat16") + +# Possible tasks are CausalLM, TextToImage, ImageClassifier, ... +# full list here: https://keras.io/api/keras_hub/models/#api-documentation +`, +]; + export const llama_cpp_python = (model: ModelData): string[] => [ `from llama_cpp import Llama diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 6de832261..42e0c1d96 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -345,16 +345,23 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { repoUrl: "https://github.com/keras-team/tf-keras", docsUrl: "https://huggingface.co/docs/hub/tf-keras", snippets: snippets.tf_keras, - filter: true, countDownloads: `path:"saved_model.pb"`, }, "keras-nlp": { prettyLabel: "KerasNLP", repoName: "KerasNLP", - repoUrl: "https://keras.io/keras_nlp/", - docsUrl: "https://github.com/keras-team/keras-nlp", + repoUrl: "https://github.com/keras-team/keras-nlp", + docsUrl: "https://keras.io/keras_nlp/", snippets: snippets.keras_nlp, }, + "keras-hub": { + prettyLabel: "KerasHub", + repoName: "KerasHub", + repoUrl: "https://github.com/keras-team/keras-hub", + docsUrl: "https://keras.io/keras_hub/", + snippets: snippets.keras_hub, + filter: true, + }, k2: { prettyLabel: "K2", repoName: "k2", From 3d57fa09842f1afa65af8b7f655626d2ec235622 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Wed, 30 Oct 2024 17:20:50 +0100 Subject: [PATCH 19/97] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20dep-publish?= =?UTF-8?q?=20to=20a=20github=20action=20(#1002)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparation for #1000 --- .github/workflows/hub-publish.yml | 38 +---- .github/workflows/inference-publish.yml | 38 +---- .github/workflows/tasks-publish.yml | 38 +---- .github/workflows/widgets-publish.yml | 176 ------------------------ package.json | 4 +- pnpm-lock.yaml | 43 +++--- scripts/check-deps.ts | 53 +++++++ 7 files changed, 83 insertions(+), 307 deletions(-) delete mode 100644 .github/workflows/widgets-publish.yml create mode 100644 scripts/check-deps.ts diff --git a/.github/workflows/hub-publish.yml b/.github/workflows/hub-publish.yml index f00c0613e..d65636020 100644 --- a/.github/workflows/hub-publish.yml +++ b/.github/workflows/hub-publish.yml @@ -53,42 +53,8 @@ jobs: git commit -m "🔖 @huggingface/hub $BUMPED_VERSION" git tag "hub-v$BUMPED_VERSION" - - name: Make sure that the latest version of @huggingface/tasks is consistent with the local version - run: | - LOCAL_TASKS_VERSION=$(node -p "require('./package.json').version") - REMOTE_TASKS_VERSION=$(npm view @huggingface/tasks version) - - # If the versions are different, error - if [ "$LOCAL_TASKS_VERSION" != "$REMOTE_TASKS_VERSION" ]; then - echo "Error: The local @huggingface/tasks package version ($LOCAL_TASKS_VERSION) differs from the remote version ($REMOTE_TASKS_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/tasks - mv huggingface-tasks-$LOCAL_TASKS_VERSION.tgz tasks-local.tgz - - npm pack @huggingface/tasks@$REMOTE_TASKS_VERSION - mv huggingface-tasks-$REMOTE_TASKS_VERSION.tgz tasks-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf tasks-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf tasks-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/tasks package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/tasks packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/tasks + - name: "Check Deps are published before publishing this package" + run: pnpm -w check-deps tasks - run: pnpm publish --no-git-checks . env: diff --git a/.github/workflows/inference-publish.yml b/.github/workflows/inference-publish.yml index ee346c24c..ce3ddd421 100644 --- a/.github/workflows/inference-publish.yml +++ b/.github/workflows/inference-publish.yml @@ -53,42 +53,8 @@ jobs: git commit -m "🔖 @huggingface/inference $BUMPED_VERSION" git tag "inference-v$BUMPED_VERSION" - - name: Make sure that the latest version of @huggingface/tasks is consistent with the local version - run: | - LOCAL_TASKS_VERSION=$(node -p "require('./package.json').version") - REMOTE_TASKS_VERSION=$(npm view @huggingface/tasks version) - - # If the versions are different, error - if [ "$LOCAL_TASKS_VERSION" != "$REMOTE_TASKS_VERSION" ]; then - echo "Error: The local @huggingface/tasks package version ($LOCAL_TASKS_VERSION) differs from the remote version ($REMOTE_TASKS_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/tasks - mv huggingface-tasks-$LOCAL_TASKS_VERSION.tgz tasks-local.tgz - - npm pack @huggingface/tasks@$REMOTE_TASKS_VERSION - mv huggingface-tasks-$REMOTE_TASKS_VERSION.tgz tasks-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf tasks-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf tasks-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/tasks package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/tasks packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/tasks + - name: "Check Deps are published before publishing this package" + run: pnpm -w check-deps gguf - run: pnpm publish --no-git-checks . env: diff --git a/.github/workflows/tasks-publish.yml b/.github/workflows/tasks-publish.yml index dbee121ea..c1c682378 100644 --- a/.github/workflows/tasks-publish.yml +++ b/.github/workflows/tasks-publish.yml @@ -50,42 +50,8 @@ jobs: git commit . -m "🔖 @huggingface/tasks $BUMPED_VERSION" git tag "tasks-v$BUMPED_VERSION" - - name: Make sure that the latest version of @huggingface/gguf is consistent with the local version - run: | - LOCAL_GGUF_VERSION=$(node -p "require('./package.json').version") - REMOTE_GGUF_VERSION=$(npm view @huggingface/gguf version) - - # If the versions are different, error - if [ "$LOCAL_GGUF_VERSION" != "$REMOTE_GGUF_VERSION" ]; then - echo "Error: The local @huggingface/gguf package version ($LOCAL_GGUF_VERSION) differs from the remote version ($REMOTE_GGUF_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/gguf - mv huggingface-gguf-$LOCAL_GGUF_VERSION.tgz gguf-local.tgz - - npm pack @huggingface/gguf@$REMOTE_GGUF_VERSION - mv huggingface-gguf-$REMOTE_GGUF_VERSION.tgz gguf-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf gguf-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf gguf-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/gguf package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/gguf packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/gguf + - name: "Check Deps are published before publishing this package" + run: pnpm -w check-deps gguf - run: pnpm publish --no-git-checks . env: diff --git a/.github/workflows/widgets-publish.yml b/.github/workflows/widgets-publish.yml deleted file mode 100644 index 502ffebe5..000000000 --- a/.github/workflows/widgets-publish.yml +++ /dev/null @@ -1,176 +0,0 @@ -name: Widgets - Version and Release - -on: - workflow_dispatch: - inputs: - newversion: - type: choice - description: "Semantic Version Bump Type" - default: patch - options: - - patch - - minor - - major - -defaults: - run: - working-directory: packages/widgets - -concurrency: - group: "push-to-main" - -jobs: - version_and_release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - # Needed to push the tag and the commit on the main branch, otherwise we get: - # > Run git push --follow-tags - # remote: error: GH006: Protected branch update failed for refs/heads/main. - # remote: error: Changes must be made through a pull request. Required status check "lint" is expected. - token: ${{ secrets.BOT_ACCESS_TOKEN }} - - run: corepack enable - - uses: actions/setup-node@v3 - with: - node-version: "20" - cache: "pnpm" - cache-dependency-path: | - packages/widgets/pnpm-lock.yaml - # setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED - registry-url: "https://registry.npmjs.org" - - run: pnpm install - - run: git config --global user.name machineuser - - run: git config --global user.email infra+machineuser@huggingface.co - - run: | - PACKAGE_VERSION=$(node -p "require('./package.json').version") - BUMPED_VERSION=$(node -p "require('semver').inc('$PACKAGE_VERSION', '${{ github.event.inputs.newversion }}')") - # Update package.json with the new version - node -e "const fs = require('fs'); const package = JSON.parse(fs.readFileSync('./package.json')); package.version = '$BUMPED_VERSION'; fs.writeFileSync('./package.json', JSON.stringify(package, null, '\t') + '\n');" - git commit . -m "🔖 @huggingface/widgets $BUMPED_VERSION" - git tag "widgets-v$BUMPED_VERSION" - - - name: Make sure that the latest version of @huggingface/tasks is consistent with the local version - run: | - LOCAL_TASKS_VERSION=$(node -p "require('./package.json').version") - REMOTE_TASKS_VERSION=$(npm view @huggingface/tasks version) - - # If the versions are different, error - if [ "$LOCAL_TASKS_VERSION" != "$REMOTE_TASKS_VERSION" ]; then - echo "Error: The local @huggingface/tasks package version ($LOCAL_TASKS_VERSION) differs from the remote version ($REMOTE_TASKS_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/tasks - mv huggingface-tasks-$LOCAL_TASKS_VERSION.tgz tasks-local.tgz - - npm pack @huggingface/tasks@$REMOTE_TASKS_VERSION - mv huggingface-tasks-$REMOTE_TASKS_VERSION.tgz tasks-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf tasks-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf tasks-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/tasks package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/tasks packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/tasks - - - name: Make sure that the latest version of @huggingface/jinja is consistent with the local version - run: | - LOCAL_JINJA_VERSION=$(node -p "require('./package.json').version") - REMOTE_JINJA_VERSION=$(npm view @huggingface/jinja version) - - # If the versions are different, error - if [ "$LOCAL_JINJA_VERSION" != "$REMOTE_JINJA_VERSION" ]; then - echo "Error: The local @huggingface/jinja package version ($LOCAL_JINJA_VERSION) differs from the remote version ($REMOTE_JINJA_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/jinja - mv huggingface-jinja-$LOCAL_JINJA_VERSION.tgz jinja-local.tgz - - npm pack @huggingface/jinja@$REMOTE_JINJA_VERSION - mv huggingface-jinja-$REMOTE_JINJA_VERSION.tgz jinja-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf jinja-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf jinja-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/jinja package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/jinja packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/jinja - - - name: Make sure that the latest version of @huggingface/inference is consistent with the local version - run: | - LOCAL_INFERENCE_VERSION=$(node -p "require('./package.json').version") - REMOTE_INFERENCE_VERSION=$(npm view @huggingface/inference version) - - # If the versions are different, error - if [ "$LOCAL_INFERENCE_VERSION" != "$REMOTE_INFERENCE_VERSION" ]; then - echo "Error: The local @huggingface/inference package version ($LOCAL_INFERENCE_VERSION) differs from the remote version ($REMOTE_INFERENCE_VERSION). Release halted." - exit 1 - fi - - npm pack @huggingface/inference - mv huggingface-inference-$LOCAL_INFERENCE_VERSION.tgz inference-local.tgz - - npm pack @huggingface/inference@$REMOTE_INFERENCE_VERSION - mv huggingface-inference-$REMOTE_INFERENCE_VERSION.tgz inference-remote.tgz - - # Compute checksum of local tar. We need to extract both tar since the remote compression might be different - tar -xf inference-local.tgz - LOCAL_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Local package checksum: $LOCAL_CHECKSUM" - - rm -Rf package - - tar -xf inference-remote.tgz - REMOTE_CHECKSUM=$(cd package && tar --mtime='1970-01-01' --mode=755 -cf - . | sha256sum | cut -d' ' -f1) - echo "Remote package checksum: $REMOTE_CHECKSUM" - - rm -Rf package - - if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - echo "Checksum Verification Failed: The local @huggingface/inference package differs from the remote version. Release halted. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM" - exit 1 - fi - echo "Checksum Verification Successful: The local and remote @huggingface/inference packages are consistent. Proceeding with the @huggingface/widgets package release. Local Checksum: $LOCAL_CHECKSUM, Remote Checksum: $REMOTE_CHECKSUM." - working-directory: packages/inference - - - run: pnpm publish --no-git-checks . - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - run: git pull --rebase && git push --follow-tags - # hack - reuse actions/setup-node@v3 just to set a new registry - - uses: actions/setup-node@v3 - with: - node-version: "20" - registry-url: "https://npm.pkg.github.com" - # Disable for now, until github supports PATs for writing github packages (https://github.com/github/roadmap/issues/558) - # - run: pnpm publish --no-git-checks . - # env: - # NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 1ffa5306f..3c54eda46 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,13 @@ "lint": "eslint --quiet --fix --ext .cjs,.ts .eslintrc.cjs", "lint:check": "eslint --ext .cjs,.ts .eslintrc.cjs", "format": "prettier --write package.json .prettierrc .vscode .eslintrc.cjs e2e .github *.md", - "format:check": "prettier --check package.json .prettierrc .vscode .eslintrc.cjs .github *.md" + "format:check": "prettier --check package.json .prettierrc .vscode .eslintrc.cjs .github *.md", + "check-deps": "tsx scripts/check-deps.ts" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", + "@types/node": "^18.16.1", "@vitest/browser": "^0.34.6", "eslint": "^8.57.0", "eslint-config-prettier": "^9.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b93520c40..183074604 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false devDependencies: + '@types/node': + specifier: ^18.16.1 + version: 18.19.61 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 version: 7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2) @@ -49,7 +52,7 @@ devDependencies: version: 5.4.2 vite: specifier: ^5.0.2 - version: 5.0.2(@types/node@20.10.0) + version: 5.0.2(@types/node@18.19.61) vitest: specifier: ^0.34.6 version: 0.34.6(@vitest/browser@0.34.6)(webdriverio@8.6.7) @@ -1181,12 +1184,8 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true - /@types/node@18.14.6: - resolution: {integrity: sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==} - dev: true - - /@types/node@20.10.0: - resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==} + /@types/node@18.19.61: + resolution: {integrity: sha512-z8fH66NcVkDzBItOao+Nyh0fiy7CYdxIyxnNCcZ60aY0I+EA/y4TSi/S/W9i8DIQvwVo7a0pgzAxmDeNnqrpkw==} dependencies: undici-types: 5.26.5 dev: true @@ -1206,14 +1205,14 @@ packages: /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 dev: true /@types/yauzl@2.10.3: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 dev: true optional: true @@ -1438,14 +1437,14 @@ packages: resolution: {integrity: sha512-vyJzqHJ5yOmfVyk5WWo6pRsJ2xhgWl3DVIBdDNR0wKrtFcm/g1jnB+pNf6Eb7NhCDh3oGul25bmhAwWDoxcFYA==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 dev: true /@wdio/types@8.4.0: resolution: {integrity: sha512-1eA0D0jS8Ttg67zB2gsZJFUcHcRz4VRjLTjxdLKh70+ZfB1+YZr9tScLgQjc+qsjsK1wKSzOz03uZiidwNnN9g==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 dev: true /@wdio/utils@8.6.6: @@ -1816,7 +1815,7 @@ packages: engines: {node: '>=12.13.0'} hasBin: true dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.3.0 @@ -2093,7 +2092,7 @@ packages: resolution: {integrity: sha512-ea6a7XqflRSVe/eJ28eaJJtjrpoqP3OeZ5fyI7SIGGYvyuw9Ha7ZTL9aMYB9TBDw15iNXjIa1a/wuOjQVd80jA==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 '@wdio/config': 8.6.6 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 @@ -4836,7 +4835,7 @@ packages: spdx-expression-parse: 3.0.1 dev: true - /vite-node@0.34.6(@types/node@20.10.0): + /vite-node@0.34.6(@types/node@18.19.61): resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -4846,7 +4845,7 @@ packages: mlly: 1.4.2 pathe: 1.1.1 picocolors: 1.0.0 - vite: 5.0.2(@types/node@20.10.0) + vite: 5.0.2(@types/node@18.19.61) transitivePeerDependencies: - '@types/node' - less @@ -4858,7 +4857,7 @@ packages: - terser dev: true - /vite@5.0.2(@types/node@20.10.0): + /vite@5.0.2(@types/node@18.19.61): resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -4886,7 +4885,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.10.0 + '@types/node': 18.19.61 esbuild: 0.19.8 postcss: 8.4.31 rollup: 4.6.0 @@ -4927,7 +4926,7 @@ packages: dependencies: '@types/chai': 4.3.11 '@types/chai-subset': 1.3.5 - '@types/node': 20.10.0 + '@types/node': 18.19.61 '@vitest/browser': 0.34.6(esbuild@0.18.20)(vitest@0.34.6) '@vitest/expect': 0.34.6 '@vitest/runner': 0.34.6 @@ -4947,8 +4946,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.7.0 - vite: 5.0.2(@types/node@20.10.0) - vite-node: 0.34.6(@types/node@20.10.0) + vite: 5.0.2(@types/node@18.19.61) + vite-node: 0.34.6(@types/node@18.19.61) webdriverio: 8.6.7(typescript@5.4.2) why-is-node-running: 2.2.2 transitivePeerDependencies: @@ -4965,7 +4964,7 @@ packages: resolution: {integrity: sha512-cly5yf5BnHOrpF+wkT7ztlt++wjws63sIyfPGPVt9MQD+yutt3zW1dB1bXgAGVVvVQUAeIkjcrIc1t8+1crFgQ==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 '@types/ws': 8.5.4 '@wdio/config': 8.6.6 '@wdio/logger': 8.6.6 @@ -4985,7 +4984,7 @@ packages: resolution: {integrity: sha512-uaBovfcJQ+g5olfveeku2GT6kGx8qZ74fVvxZVRM/6FYWK6eMT//MPVnmM9UducYHApcxXFULrA+UTtOY5EEag==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.14.6 + '@types/node': 18.19.61 '@wdio/config': 8.6.6 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 diff --git a/scripts/check-deps.ts b/scripts/check-deps.ts new file mode 100644 index 000000000..dd29a34b3 --- /dev/null +++ b/scripts/check-deps.ts @@ -0,0 +1,53 @@ +import { execSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import { parseArgs } from "node:util"; + +const args = parseArgs({ + allowPositionals: true, +}); + +const dep = args.positionals[0]; + +if (!dep) { + console.error("Error: No dependency specified."); + process.exit(1); +} + +process.chdir(`./packages/${dep}`); + +const localPackageJson = readFileSync(`./package.json`, "utf-8"); +const localVersion = JSON.parse(localPackageJson).version as string; +const remoteVersion = execSync(`npm view @huggingface/${dep} version`).toString().trim(); + +if (localVersion !== remoteVersion) { + console.error( + `Error: The local @huggingface/${dep} package version (${localVersion}) differs from the remote version (${remoteVersion}). Release halted.` + ); + process.exit(1); +} + +execSync(`npm pack`); +execSync(`mv huggingface-${dep}-${localVersion}.tgz ${dep}-local.tgz`); + +execSync(`npm pack @huggingface/${dep}@${remoteVersion}`); +execSync(`mv huggingface-${dep}-${remoteVersion}.tgz ${dep}-remote.tgz`); + +execSync(`rm -Rf local && mkdir local && tar -xf ${dep}-local.tgz -C local`); +execSync(`rm -Rf remote && mkdir remote && tar -xf ${dep}-remote.tgz -C remote`); + +// Remove package.json files because they're modified by npm +execSync(`rm local/package/package.json`); +execSync(`rm remote/package/package.json`); + +try { + execSync("diff --brief -r local remote").toString(); +} catch (e) { + console.error(e.output.filter(Boolean).join("\n")); + console.error(`Error: The local and remote @huggingface/${dep} packages are inconsistent. Release halted.`); + process.exit(1); +} + +console.log(`The local and remote @huggingface/${dep} packages are consistent.`); + +execSync(`rm -Rf local`); +execSync(`rm -Rf remote`); From 50e0374ecf009aea06f7d42147f6477aef80c807 Mon Sep 17 00:00:00 2001 From: ved-genmo <164923711+ved-genmo@users.noreply.github.com> Date: Thu, 31 Oct 2024 06:11:06 -0700 Subject: [PATCH 20/97] Add support for mochi-1-preview (genmo) to huggingface.js (#981) Add mochi-1-preview to huggingface.js. --------- Co-authored-by: Lucain Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 42e0c1d96..1c421f901 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -693,6 +693,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: false, countDownloads: `path_extension:"safetensors" OR path_extension:"pt"`, }, + "genmo": { + prettyLabel: "Genmo", + repoName: "Genmo", + repoUrl: "https://github.com/genmoai/models", + filter: false, + countDownloads: `path:"vae_stats.json"`, + }, tensorflowtts: { prettyLabel: "TensorFlowTTS", repoName: "TensorFlowTTS", From d0e641cc7ce1737a3c92b188fa5051f17d2f5b0b Mon Sep 17 00:00:00 2001 From: Lucain Date: Thu, 31 Oct 2024 16:52:08 +0100 Subject: [PATCH 21/97] Update CODEOWNERS :'( (#1006) :sob: --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 80148fb6c..b208691e4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,7 +4,7 @@ # Ownership for the Tasks Package -/packages/tasks/ @osanseviero @SBrandeis @gary149 @Wauplin @julien-c @pcuenca +/packages/tasks/ @SBrandeis @gary149 @Wauplin @julien-c @pcuenca # Ownership for the Hub Package From e57f6ef4ec8c0075d0b1f478aaadb14f0b19355a Mon Sep 17 00:00:00 2001 From: Julien Chaumond Date: Fri, 1 Nov 2024 20:42:00 +0100 Subject: [PATCH 22/97] add @ngxson to codeowners for tasks&gguf (#1009) --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index b208691e4..bbcb48eb7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,7 +4,7 @@ # Ownership for the Tasks Package -/packages/tasks/ @SBrandeis @gary149 @Wauplin @julien-c @pcuenca +/packages/tasks/ @SBrandeis @gary149 @Wauplin @julien-c @pcuenca @ngxson # Ownership for the Hub Package @@ -20,7 +20,7 @@ # Ownership for the gguf Package -/packages/gguf @mishig25 @julien-c +/packages/gguf @mishig25 @ngxson @julien-c # Ownership for the space-header Package /packages/space-header @enzostvs From 56f465ec7b10c0a0342935dcd3803378e706dbe4 Mon Sep 17 00:00:00 2001 From: Julian Quevedo Date: Mon, 4 Nov 2024 00:16:01 -0800 Subject: [PATCH 23/97] Add countDownloads for Oasis (#1007) This PR is intended to add download counting support for https://huggingface.co/Etched/oasis-500m. It matches `.pt` files in order to match both the autoencoder and the diffusion model. The relevant github repository (used for inferencing the model) is https://github.com/etched-ai/open-oasis. --------- Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 1c421f901..f98f979ad 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -469,6 +469,12 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: true, countDownloads: `path_extension:"nemo" OR path:"model_config.yaml"`, }, + open-oasis: { + prettyLabel: "open-oasis", + repoName: "open-oasis", + repoUrl: "https://github.com/etched-ai/open-oasis", + countDownloads: `path:"oasis500m.pt"`, + }, open_clip: { prettyLabel: "OpenCLIP", repoName: "OpenCLIP", From 2d3a655336c0476d90001d977a2cdc00523de602 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Mon, 4 Nov 2024 09:30:51 +0100 Subject: [PATCH 24/97] =?UTF-8?q?=F0=9F=92=A5=20Switch=20gguf=20&=20tasks?= =?UTF-8?q?=20interdependency=20(#1004)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cc @ngxson too (you can add yourself to CODEOWNERS for gguf maybe :) ) Move the functions needed by `@huggingface/tasks` directly into `@huggingface/tasks`. Now `@hugginface/gguf` depends on `@huggingface/tasks` and not the other way around. The move is minimal, more could be moved. (Or a fancy solution with shared folders, but fancy solutions can become complicated esp with publishing source code along with dist. Or we could just duplicate the code, and maybe add CI check to ensure consistency) --- .github/workflows/gguf-publish.yml | 4 +++ .github/workflows/tasks-publish.yml | 3 --- .github/workflows/test.yml | 2 +- packages/gguf/package.json | 4 ++- packages/gguf/pnpm-lock.yaml | 5 ++++ packages/gguf/src/gguf.ts | 12 ++------- packages/gguf/src/types.ts | 34 ++---------------------- packages/tasks/package.json | 3 --- packages/tasks/pnpm-lock.yaml | 5 ---- packages/tasks/src/gguf.ts | 40 +++++++++++++++++++++++++++++ packages/tasks/src/index.ts | 2 ++ packages/tasks/src/local-apps.ts | 2 +- 12 files changed, 60 insertions(+), 56 deletions(-) create mode 100644 packages/tasks/src/gguf.ts diff --git a/.github/workflows/gguf-publish.yml b/.github/workflows/gguf-publish.yml index f4791ac5d..383d98b47 100644 --- a/.github/workflows/gguf-publish.yml +++ b/.github/workflows/gguf-publish.yml @@ -49,6 +49,10 @@ jobs: node -e "const fs = require('fs'); const package = JSON.parse(fs.readFileSync('./package.json')); package.version = '$BUMPED_VERSION'; fs.writeFileSync('./package.json', JSON.stringify(package, null, '\t') + '\n');" git commit . -m "🔖 @huggingface/gguf $BUMPED_VERSION" git tag "gguf-v$BUMPED_VERSION" + + - name: "Check Deps are published before publishing this package" + run: pnpm -w check-deps tasks + - run: pnpm publish --no-git-checks . env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/tasks-publish.yml b/.github/workflows/tasks-publish.yml index c1c682378..dca33c507 100644 --- a/.github/workflows/tasks-publish.yml +++ b/.github/workflows/tasks-publish.yml @@ -50,9 +50,6 @@ jobs: git commit . -m "🔖 @huggingface/tasks $BUMPED_VERSION" git tag "tasks-v$BUMPED_VERSION" - - name: "Check Deps are published before publishing this package" - run: pnpm -w check-deps gguf - - run: pnpm publish --no-git-checks . env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eea042652..99fa2469d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -105,7 +105,7 @@ jobs: run: | sleep 3 pnpm i --filter root --filter inference... --filter hub... --frozen-lockfile - pnpm --filter inference --filter hub --filter tasks --filter gguf publish --force --no-git-checks --registry http://localhost:4874/ + pnpm --filter inference --filter hub --filter tasks publish --force --no-git-checks --registry http://localhost:4874/ - name: E2E test - test yarn install working-directory: e2e/ts diff --git a/packages/gguf/package.json b/packages/gguf/package.json index 53ae965b2..af13d7096 100644 --- a/packages/gguf/package.json +++ b/packages/gguf/package.json @@ -27,7 +27,6 @@ }, "source": "index.ts", "scripts": { - "prepare": "pnpm run build", "lint": "eslint --quiet --fix --ext .cjs,.ts .", "lint:check": "eslint --ext .cjs,.ts .", "format": "prettier --write .", @@ -50,6 +49,9 @@ ], "author": "Hugging Face", "license": "MIT", + "dependencies": { + "@huggingface/tasks": "workspace:^" + }, "devDependencies": { "@types/node": "^20.12.8" } diff --git a/packages/gguf/pnpm-lock.yaml b/packages/gguf/pnpm-lock.yaml index ebb2107de..c96b1898a 100644 --- a/packages/gguf/pnpm-lock.yaml +++ b/packages/gguf/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + '@huggingface/tasks': + specifier: workspace:^ + version: link:../tasks + devDependencies: '@types/node': specifier: ^20.12.8 diff --git a/packages/gguf/src/gguf.ts b/packages/gguf/src/gguf.ts index 0efd43aaa..d83b405da 100644 --- a/packages/gguf/src/gguf.ts +++ b/packages/gguf/src/gguf.ts @@ -1,11 +1,12 @@ import type { MetadataValue, Version, GGUFMetadata, GGUFTensorInfo, GGUFParseOutput } from "./types"; -import { GGMLQuantizationType, GGUFValueType } from "./types"; +import { GGUFValueType } from "./types"; import { isBackend } from "./utils/isBackend"; import { promisesQueue } from "./utils/promisesQueue"; export type { MetadataBaseValue, MetadataValue, Version, GGUFMetadata, GGUFTensorInfo, GGUFParseOutput } from "./types"; export { GGUFValueType, GGMLFileQuantizationType, GGMLQuantizationType, Architecture } from "./types"; export { GGUF_QUANT_DESCRIPTIONS } from "./quant-descriptions"; +export { parseGGUFQuantLabel, GGUF_QUANT_RE, GGUF_QUANT_RE_GLOBAL } from "@huggingface/tasks"; export const RE_GGUF_FILE = /\.gguf$/; export const RE_GGUF_SHARD_FILE = /^(?.*?)-(?\d{5})-of-(?\d{5})\.gguf$/; @@ -29,15 +30,6 @@ export function parseGgufShardFilename(filename: string): GgufShardFileInfo | nu return null; } -const ggufQuants = Object.values(GGMLQuantizationType).filter((v): v is string => typeof v === "string"); -export const GGUF_QUANT_RE = new RegExp(`(?${ggufQuants.join("|")})` + "(_(?[A-Z]+))?"); -export const GGUF_QUANT_RE_GLOBAL = new RegExp(GGUF_QUANT_RE, "g"); - -export function parseGGUFQuantLabel(fname: string): string | undefined { - const quantLabel = fname.toUpperCase().match(GGUF_QUANT_RE_GLOBAL)?.at(-1); // if there is multiple quant substrings in a name, we prefer the last one - return quantLabel; -} - const isVersion = (version: number): version is Version => version === 1 || version === 2 || version === 3; /** diff --git a/packages/gguf/src/types.ts b/packages/gguf/src/types.ts index 02872b95c..4a6b40e16 100644 --- a/packages/gguf/src/types.ts +++ b/packages/gguf/src/types.ts @@ -1,5 +1,7 @@ import type { TransformerLLM } from "./transformer-llm"; import { LLM_ARCHITECTURES } from "./transformer-llm"; +import type { GGMLQuantizationType } from "@huggingface/tasks"; +export { GGMLQuantizationType } from "@huggingface/tasks"; export type MetadataBaseValue = string | number | bigint | boolean; export type MetadataValue = MetadataBaseValue | MetadataBaseValue[] | MetadataValue[]; /// recursive as arrays can be nested. @@ -45,38 +47,6 @@ export enum GGMLFileQuantizationType { MOSTLY_Q4_0_8_8 = 35, } -export enum GGMLQuantizationType { - F32 = 0, - F16 = 1, - Q4_0 = 2, - Q4_1 = 3, - Q5_0 = 6, - Q5_1 = 7, - Q8_0 = 8, - Q8_1 = 9, - Q2_K = 10, - Q3_K = 11, - Q4_K = 12, - Q5_K = 13, - Q6_K = 14, - Q8_K = 15, - IQ2_XXS = 16, - IQ2_XS = 17, - IQ3_XXS = 18, - IQ1_S = 19, - IQ4_NL = 20, - IQ3_S = 21, - IQ2_S = 22, - IQ4_XS = 23, - I8 = 24, - I16 = 25, - I32 = 26, - I64 = 27, - F64 = 28, - IQ1_M = 29, - BF16 = 30, -} - export enum GGUFValueType { UINT8 = 0, INT8 = 1, diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 318365a7f..cde12eeaf 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -51,8 +51,5 @@ "@types/node": "^20.11.5", "quicktype-core": "https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz", "type-fest": "^3.13.1" - }, - "dependencies": { - "@huggingface/gguf": "workspace:^" } } diff --git a/packages/tasks/pnpm-lock.yaml b/packages/tasks/pnpm-lock.yaml index 2d5435a89..741ee9a42 100644 --- a/packages/tasks/pnpm-lock.yaml +++ b/packages/tasks/pnpm-lock.yaml @@ -4,11 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@huggingface/gguf': - specifier: workspace:^ - version: link:../gguf - devDependencies: '@types/node': specifier: ^20.11.5 diff --git a/packages/tasks/src/gguf.ts b/packages/tasks/src/gguf.ts new file mode 100644 index 000000000..51ca8e841 --- /dev/null +++ b/packages/tasks/src/gguf.ts @@ -0,0 +1,40 @@ +export enum GGMLQuantizationType { + F32 = 0, + F16 = 1, + Q4_0 = 2, + Q4_1 = 3, + Q5_0 = 6, + Q5_1 = 7, + Q8_0 = 8, + Q8_1 = 9, + Q2_K = 10, + Q3_K = 11, + Q4_K = 12, + Q5_K = 13, + Q6_K = 14, + Q8_K = 15, + IQ2_XXS = 16, + IQ2_XS = 17, + IQ3_XXS = 18, + IQ1_S = 19, + IQ4_NL = 20, + IQ3_S = 21, + IQ2_S = 22, + IQ4_XS = 23, + I8 = 24, + I16 = 25, + I32 = 26, + I64 = 27, + F64 = 28, + IQ1_M = 29, + BF16 = 30, +} + +const ggufQuants = Object.values(GGMLQuantizationType).filter((v): v is string => typeof v === "string"); +export const GGUF_QUANT_RE = new RegExp(`(?${ggufQuants.join("|")})` + "(_(?[A-Z]+))?"); +export const GGUF_QUANT_RE_GLOBAL = new RegExp(GGUF_QUANT_RE, "g"); + +export function parseGGUFQuantLabel(fname: string): string | undefined { + const quantLabel = fname.toUpperCase().match(GGUF_QUANT_RE_GLOBAL)?.at(-1); // if there is multiple quant substrings in a name, we prefer the last one + return quantLabel; +} diff --git a/packages/tasks/src/index.ts b/packages/tasks/src/index.ts index cefebfaea..e80a9013f 100644 --- a/packages/tasks/src/index.ts +++ b/packages/tasks/src/index.ts @@ -42,6 +42,8 @@ export type { export { SPECIAL_TOKENS_ATTRIBUTES } from "./tokenizer-data"; import * as snippets from "./snippets"; +export * from "./gguf"; + export { snippets }; export { SKUS, DEFAULT_MEMORY_OPTIONS } from "./hardware"; diff --git a/packages/tasks/src/local-apps.ts b/packages/tasks/src/local-apps.ts index 3fe1cbfac..683b62989 100644 --- a/packages/tasks/src/local-apps.ts +++ b/packages/tasks/src/local-apps.ts @@ -1,6 +1,6 @@ +import { parseGGUFQuantLabel } from "./gguf"; import type { ModelData } from "./model-data"; import type { PipelineType } from "./pipelines"; -import { parseGGUFQuantLabel } from "@huggingface/gguf"; export interface LocalAppSnippet { /** From b166663225b0979a3bce603607cd1e84cb9c347c Mon Sep 17 00:00:00 2001 From: coyotte508 Date: Mon, 4 Nov 2024 09:38:54 +0100 Subject: [PATCH 25/97] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/src/model-libraries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index f98f979ad..224759c36 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -469,7 +469,7 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: true, countDownloads: `path_extension:"nemo" OR path:"model_config.yaml"`, }, - open-oasis: { + "open-oasis": { prettyLabel: "open-oasis", repoName: "open-oasis", repoUrl: "https://github.com/etched-ai/open-oasis", @@ -699,7 +699,7 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: false, countDownloads: `path_extension:"safetensors" OR path_extension:"pt"`, }, - "genmo": { + genmo: { prettyLabel: "Genmo", repoName: "Genmo", repoUrl: "https://github.com/genmoai/models", From 138366b7a14ce59974fd6826e553027e5a835273 Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 4 Nov 2024 08:42:15 +0000 Subject: [PATCH 26/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.12.?= =?UTF-8?q?29?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index cde12eeaf..2c7ad2878 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.12.28", + "version": "0.12.29", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From ea047d1b9b8f0615db159d1a35b7ca043d0829dd Mon Sep 17 00:00:00 2001 From: Mishig Date: Mon, 4 Nov 2024 16:23:30 +0100 Subject: [PATCH 27/97] [Conversational snippet] Fix, refactor, & add tests (#1003) ### Description [Conversational snippet] Fix, refactor, & add tests closes https://github.com/huggingface/huggingface.js/issues/1010 1. Fixes an error https://github.com/huggingface/huggingface.js/pull/1003/files#r1824269481 2. Redo https://github.com/huggingface/huggingface.js/pull/1003/files#r1824270922 3. Add tests --------- Co-authored-by: Nicholas Broad --- packages/tasks/package.json | 1 + packages/tasks/src/snippets/common.ts | 78 +++++++------------- packages/tasks/src/snippets/curl.spec.ts | 68 +++++++++++++++++ packages/tasks/src/snippets/curl.ts | 8 +- packages/tasks/src/snippets/inputs.ts | 1 + packages/tasks/src/snippets/js.spec.ts | 86 ++++++++++++++++++++++ packages/tasks/src/snippets/js.ts | 6 +- packages/tasks/src/snippets/python.spec.ts | 78 ++++++++++++++++++++ packages/tasks/src/snippets/python.ts | 15 +--- 9 files changed, 269 insertions(+), 72 deletions(-) create mode 100644 packages/tasks/src/snippets/curl.spec.ts create mode 100644 packages/tasks/src/snippets/js.spec.ts create mode 100644 packages/tasks/src/snippets/python.spec.ts diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 2c7ad2878..305e410f1 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -30,6 +30,7 @@ "watch": "npm-run-all --parallel watch:export watch:types", "prepare": "pnpm run build", "check": "tsc", + "test": "vitest run", "inference-codegen": "tsx scripts/inference-codegen.ts && prettier --write src/tasks/*/inference.ts", "inference-tgi-import": "tsx scripts/inference-tgi-import.ts && prettier --write src/tasks/text-generation/spec/*.json && prettier --write src/tasks/chat-completion/spec/*.json", "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write src/tasks/feature-extraction/spec/*.json" diff --git a/packages/tasks/src/snippets/common.ts b/packages/tasks/src/snippets/common.ts index 24b061340..0f82db815 100644 --- a/packages/tasks/src/snippets/common.ts +++ b/packages/tasks/src/snippets/common.ts @@ -1,63 +1,39 @@ import type { ChatCompletionInputMessage, GenerationParameters } from "../tasks"; -export interface StringifyMessagesOptions { - sep: string; - start: string; - end: string; - attributeKeyQuotes?: boolean; - customContentEscaper?: (str: string) => string; -} - -export function stringifyMessages(messages: ChatCompletionInputMessage[], opts: StringifyMessagesOptions): string { - const keyRole = opts.attributeKeyQuotes ? `"role"` : "role"; - const keyContent = opts.attributeKeyQuotes ? `"content"` : "content"; - - const messagesStringified = messages.map(({ role, content }) => { - if (typeof content === "string") { - content = JSON.stringify(content).slice(1, -1); - if (opts.customContentEscaper) { - content = opts.customContentEscaper(content); - } - return `{ ${keyRole}: "${role}", ${keyContent}: "${content}" }`; - } else { - 2; - content = content.map(({ image_url, text, type }) => ({ - type, - image_url, - ...(text ? { text: JSON.stringify(text).slice(1, -1) } : undefined), - })); - content = JSON.stringify(content).slice(1, -1); - if (opts.customContentEscaper) { - content = opts.customContentEscaper(content); - } - return `{ ${keyRole}: "${role}", ${keyContent}: [${content}] }`; - } - }); - - return opts.start + messagesStringified.join(opts.sep) + opts.end; +export function stringifyMessages( + messages: ChatCompletionInputMessage[], + opts?: { + indent?: string; + attributeKeyQuotes?: boolean; + customContentEscaper?: (str: string) => string; + } +): string { + let messagesStr = JSON.stringify(messages, null, "\t"); + if (opts?.indent) { + messagesStr = messagesStr.replaceAll("\n", `\n${opts.indent}`); + } + if (!opts?.attributeKeyQuotes) { + messagesStr = messagesStr.replace(/"([^"]+)":/g, "$1:"); + } + if (opts?.customContentEscaper) { + messagesStr = opts.customContentEscaper(messagesStr); + } + return messagesStr; } type PartialGenerationParameters = Partial>; -export interface StringifyGenerationConfigOptions { - sep: string; - start: string; - end: string; - attributeValueConnector: string; - attributeKeyQuotes?: boolean; -} - export function stringifyGenerationConfig( config: PartialGenerationParameters, - opts: StringifyGenerationConfigOptions + opts: { + indent: string; + attributeValueConnector: string; + attributeKeyQuotes?: boolean; + } ): string { const quote = opts.attributeKeyQuotes ? `"` : ""; - return ( - opts.start + - Object.entries(config) - .map(([key, val]) => `${quote}${key}${quote}${opts.attributeValueConnector}${val}`) - .join(opts.sep) + - opts.end - ); + return Object.entries(config) + .map(([key, val]) => `${quote}${key}${quote}${opts.attributeValueConnector}${val}`) + .join(`,${opts.indent}`); } diff --git a/packages/tasks/src/snippets/curl.spec.ts b/packages/tasks/src/snippets/curl.spec.ts new file mode 100644 index 000000000..0b854dbb8 --- /dev/null +++ b/packages/tasks/src/snippets/curl.spec.ts @@ -0,0 +1,68 @@ +import type { ModelDataMinimal } from "./types"; +import { describe, expect, it } from "vitest"; +import { snippetTextGeneration } from "./curl"; + +describe("inference API snippets", () => { + it("conversational llm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetTextGeneration(model, "api_token"); + + expect(snippet.content) + .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \\ +-H "Authorization: Bearer api_token" \\ +-H 'Content-Type: application/json' \\ +--data '{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "messages": [ + { + "role": "user", + "content": "What is the capital of France?" + } + ], + "max_tokens": 500, + "stream": true +}'`); + }); + + it("conversational vlm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetTextGeneration(model, "api_token"); + + expect(snippet.content) + .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions' \\ +-H "Authorization: Bearer api_token" \\ +-H 'Content-Type: application/json' \\ +--data '{ + "model": "meta-llama/Llama-3.2-11B-Vision-Instruct", + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + "max_tokens": 500, + "stream": true +}'`); + }); +}); diff --git a/packages/tasks/src/snippets/curl.ts b/packages/tasks/src/snippets/curl.ts index af4ada267..28f8a59c7 100644 --- a/packages/tasks/src/snippets/curl.ts +++ b/packages/tasks/src/snippets/curl.ts @@ -41,16 +41,12 @@ export const snippetTextGeneration = ( --data '{ "model": "${model.id}", "messages": ${stringifyMessages(messages, { - sep: ",\n\t\t", - start: `[\n\t\t`, - end: `\n\t]`, + indent: "\t", attributeKeyQuotes: true, customContentEscaper: (str) => str.replace(/'/g, "'\\''"), })}, ${stringifyGenerationConfig(config, { - sep: ",\n ", - start: "", - end: "", + indent: "\n ", attributeKeyQuotes: true, attributeValueConnector: ": ", })}, diff --git a/packages/tasks/src/snippets/inputs.ts b/packages/tasks/src/snippets/inputs.ts index 6a0404bdf..70afde388 100644 --- a/packages/tasks/src/snippets/inputs.ts +++ b/packages/tasks/src/snippets/inputs.ts @@ -128,6 +128,7 @@ const modelInputSnippets: { "tabular-classification": inputsTabularPrediction, "text-classification": inputsTextClassification, "text-generation": inputsTextGeneration, + "image-text-to-text": inputsTextGeneration, "text-to-image": inputsTextToImage, "text-to-speech": inputsTextToSpeech, "text-to-audio": inputsTextToAudio, diff --git a/packages/tasks/src/snippets/js.spec.ts b/packages/tasks/src/snippets/js.spec.ts new file mode 100644 index 000000000..778070721 --- /dev/null +++ b/packages/tasks/src/snippets/js.spec.ts @@ -0,0 +1,86 @@ +import type { InferenceSnippet, ModelDataMinimal } from "./types"; +import { describe, expect, it } from "vitest"; +import { snippetTextGeneration } from "./js"; + +describe("inference API snippets", () => { + it("conversational llm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetTextGeneration(model, "api_token") as InferenceSnippet[]; + + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + +const client = new HfInference("api_token") + +let out = ""; + +const stream = client.chatCompletionStream({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +}`); + }); + + it("conversational vlm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetTextGeneration(model, "api_token") as InferenceSnippet[]; + + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + +const client = new HfInference("api_token") + +let out = ""; + +const stream = client.chatCompletionStream({ + model: "meta-llama/Llama-3.2-11B-Vision-Instruct", + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence." + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + max_tokens: 500 +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +}`); + }); +}); diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index c261e08a1..fdf25b46c 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -42,7 +42,7 @@ export const snippetTextGeneration = ( const streaming = opts?.streaming ?? true; const exampleMessages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; const messages = opts?.messages ?? exampleMessages; - const messagesStr = stringifyMessages(messages, { sep: ",\n\t\t", start: "[\n\t\t", end: "\n\t]" }); + const messagesStr = stringifyMessages(messages, { indent: "\t" }); const config = { ...(opts?.temperature ? { temperature: opts.temperature } : undefined), @@ -50,9 +50,7 @@ export const snippetTextGeneration = ( ...(opts?.top_p ? { top_p: opts.top_p } : undefined), }; const configStr = stringifyGenerationConfig(config, { - sep: ",\n\t", - start: "", - end: "", + indent: "\n\t", attributeValueConnector: ": ", }); diff --git a/packages/tasks/src/snippets/python.spec.ts b/packages/tasks/src/snippets/python.spec.ts new file mode 100644 index 000000000..3f1ee4979 --- /dev/null +++ b/packages/tasks/src/snippets/python.spec.ts @@ -0,0 +1,78 @@ +import type { ModelDataMinimal } from "./types"; +import { describe, expect, it } from "vitest"; +import { snippetConversational } from "./python"; + +describe("inference API snippets", () => { + it("conversational llm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetConversational(model, "api_token"); + + expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="")`); + }); + + it("conversational vlm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetConversational(model, "api_token"); + + expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.2-11B-Vision-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="")`); + }); +}); diff --git a/packages/tasks/src/snippets/python.ts b/packages/tasks/src/snippets/python.ts index d2b0f2585..31ce47a10 100644 --- a/packages/tasks/src/snippets/python.ts +++ b/packages/tasks/src/snippets/python.ts @@ -18,12 +18,7 @@ export const snippetConversational = ( const streaming = opts?.streaming ?? true; const exampleMessages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; const messages = opts?.messages ?? exampleMessages; - const messagesStr = stringifyMessages(messages, { - sep: ",\n\t", - start: `[\n\t`, - end: `\n]`, - attributeKeyQuotes: true, - }); + const messagesStr = stringifyMessages(messages, { attributeKeyQuotes: true }); const config = { ...(opts?.temperature ? { temperature: opts.temperature } : undefined), @@ -31,9 +26,7 @@ export const snippetConversational = ( ...(opts?.top_p ? { top_p: opts.top_p } : undefined), }; const configStr = stringifyGenerationConfig(config, { - sep: ",\n\t", - start: "", - end: "", + indent: "\n\t", attributeValueConnector: "=", }); @@ -55,7 +48,7 @@ stream = client.chat.completions.create( ) for chunk in stream: - print(chunk.choices[0].delta.content)`, + print(chunk.choices[0].delta.content, end="")`, }, { client: "openai", @@ -76,7 +69,7 @@ stream = client.chat.completions.create( ) for chunk in stream: - print(chunk.choices[0].delta.content)`, + print(chunk.choices[0].delta.content, end="")`, }, ]; } else { From 8eea49e7b77482d2d0e9a192fa35fcd6af78f767 Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 4 Nov 2024 15:24:21 +0000 Subject: [PATCH 28/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.12.?= =?UTF-8?q?30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 305e410f1..a92e07e74 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.12.29", + "version": "0.12.30", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From f2795a84744adc7f16cf5442faa5fca0e4e0ef54 Mon Sep 17 00:00:00 2001 From: Lucain Date: Tue, 5 Nov 2024 11:27:48 +0100 Subject: [PATCH 29/97] Fix client in VLM JS inference snippet (#1013) Small typo. In JS, the library should be `huggingface.js` not `huggingface_hub`. --- packages/tasks/src/snippets/js.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index fdf25b46c..5baa7ee85 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -57,7 +57,7 @@ export const snippetTextGeneration = ( if (streaming) { return [ { - client: "huggingface_hub", + client: "huggingface.js", content: `import { HfInference } from "@huggingface/inference" const client = new HfInference("${accessToken || `{API_TOKEN}`}") @@ -108,7 +108,7 @@ for await (const chunk of stream) { } else { return [ { - client: "huggingface_hub", + client: "huggingface.js", content: `import { HfInference } from '@huggingface/inference' const client = new HfInference("${accessToken || `{API_TOKEN}`}") From bc7381c50a4796abc58a531e6d832ef4afdc6cb6 Mon Sep 17 00:00:00 2001 From: Borg93 <48671678+Borg93@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:55:44 +0100 Subject: [PATCH 30/97] Add HTRflow as a library (#1008) This PR adds https://github.com/AI-Riksarkivet/htrflow/ as a library. --------- Co-authored-by: vb Co-authored-by: Lucain --- packages/tasks/src/model-libraries-snippets.ts | 17 +++++++++++++++++ packages/tasks/src/model-libraries.ts | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index fc4280533..fa5c87753 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -363,6 +363,23 @@ export const gliner = (model: ModelData): string[] => [ model = GLiNER.from_pretrained("${model.id}")`, ]; +export const htrflow = (model: ModelData): string[] => [ + `# CLI usage +# see docs: https://ai-riksarkivet.github.io/htrflow/latest/getting_started/quick_start.html +htrflow pipeline `, + `# Python usage +from htrflow.pipeline.pipeline import Pipeline +from htrflow.pipeline.steps import Task +from htrflow.models.framework.model import ModelClass + +pipeline = Pipeline( + [ + Task( + ModelClass, {"model": "${model.id}"}, {} + ), + ])`, +]; + export const keras = (model: ModelData): string[] => [ `# Available backend options are: "jax", "torch", "tensorflow". import os diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 224759c36..e25550640 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -317,6 +317,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { docsUrl: "https://hezarai.github.io/hezar", countDownloads: `path:"model_config.yaml" OR path:"embedding/embedding_config.yaml"`, }, + htrflow: { + prettyLabel: "HTRflow", + repoName: "HTRflow", + repoUrl: "https://github.com/AI-Riksarkivet/htrflow", + docsUrl: "https://ai-riksarkivet.github.io/htrflow", + snippets: snippets.htrflow, + }, "hunyuan-dit": { prettyLabel: "HunyuanDiT", repoName: "HunyuanDiT", From 4606df37d6e65c6be10dd51974fd82a92b4e9dc1 Mon Sep 17 00:00:00 2001 From: machineuser Date: Sun, 10 Nov 2024 11:38:24 +0000 Subject: [PATCH 31/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index a92e07e74..ad7193d93 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.12.30", + "version": "0.13.0", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 27b995dea8b1d377c5b77a97fb5f6db3af0bf3ae Mon Sep 17 00:00:00 2001 From: Julian Quevedo Date: Mon, 11 Nov 2024 22:57:04 -0800 Subject: [PATCH 32/97] Track oasis .safetensors instead of .pt (#1018) Hello! We recently updated our model (https://huggingface.co/Etched/oasis-500m/tree/main) to use the safetensors format instead of pickle. We want to make the .safetensors the default and remove the .pt, and so this PR allows download counting on the .safetensors instead. Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index e25550640..168f1471a 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -480,7 +480,7 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { prettyLabel: "open-oasis", repoName: "open-oasis", repoUrl: "https://github.com/etched-ai/open-oasis", - countDownloads: `path:"oasis500m.pt"`, + countDownloads: `path:"oasis500m.safetensors"`, }, open_clip: { prettyLabel: "OpenCLIP", From f00b6aab2a9ae7cd20847b149f91cf8c268c984f Mon Sep 17 00:00:00 2001 From: Mishig Date: Thu, 14 Nov 2024 10:18:02 -0400 Subject: [PATCH 33/97] [Conversational Snippet] Test non-streaming versions (#1027) [Conversational Snippet] Test non-streaming versions --- packages/tasks/src/snippets/curl.spec.ts | 32 +++++++++- packages/tasks/src/snippets/curl.ts | 8 ++- packages/tasks/src/snippets/js.spec.ts | 68 +++++++++++++++++++++- packages/tasks/src/snippets/js.ts | 7 ++- packages/tasks/src/snippets/python.spec.ts | 37 ++++++++++-- 5 files changed, 137 insertions(+), 15 deletions(-) diff --git a/packages/tasks/src/snippets/curl.spec.ts b/packages/tasks/src/snippets/curl.spec.ts index 0b854dbb8..19eaf76e3 100644 --- a/packages/tasks/src/snippets/curl.spec.ts +++ b/packages/tasks/src/snippets/curl.spec.ts @@ -1,6 +1,6 @@ import type { ModelDataMinimal } from "./types"; import { describe, expect, it } from "vitest"; -import { snippetTextGeneration } from "./curl"; +import { getCurlInferenceSnippet } from "./curl"; describe("inference API snippets", () => { it("conversational llm", async () => { @@ -10,7 +10,7 @@ describe("inference API snippets", () => { tags: ["conversational"], inference: "", }; - const snippet = snippetTextGeneration(model, "api_token"); + const snippet = getCurlInferenceSnippet(model, "api_token"); expect(snippet.content) .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \\ @@ -29,6 +29,32 @@ describe("inference API snippets", () => { }'`); }); + it("conversational llm non-streaming", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = getCurlInferenceSnippet(model, "api_token", { streaming: false }); + + expect(snippet.content) + .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \\ +-H "Authorization: Bearer api_token" \\ +-H 'Content-Type: application/json' \\ +--data '{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "messages": [ + { + "role": "user", + "content": "What is the capital of France?" + } + ], + "max_tokens": 500, + "stream": false +}'`); + }); + it("conversational vlm", async () => { const model: ModelDataMinimal = { id: "meta-llama/Llama-3.2-11B-Vision-Instruct", @@ -36,7 +62,7 @@ describe("inference API snippets", () => { tags: ["conversational"], inference: "", }; - const snippet = snippetTextGeneration(model, "api_token"); + const snippet = getCurlInferenceSnippet(model, "api_token"); expect(snippet.content) .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions' \\ diff --git a/packages/tasks/src/snippets/curl.ts b/packages/tasks/src/snippets/curl.ts index 28f8a59c7..8b04d55d1 100644 --- a/packages/tasks/src/snippets/curl.ts +++ b/packages/tasks/src/snippets/curl.ts @@ -105,9 +105,13 @@ export const curlSnippets: Partial< "image-segmentation": snippetFile, }; -export function getCurlInferenceSnippet(model: ModelDataMinimal, accessToken: string): InferenceSnippet { +export function getCurlInferenceSnippet( + model: ModelDataMinimal, + accessToken: string, + opts?: Record +): InferenceSnippet { return model.pipeline_tag && model.pipeline_tag in curlSnippets - ? curlSnippets[model.pipeline_tag]?.(model, accessToken) ?? { content: "" } + ? curlSnippets[model.pipeline_tag]?.(model, accessToken, opts) ?? { content: "" } : { content: "" }; } diff --git a/packages/tasks/src/snippets/js.spec.ts b/packages/tasks/src/snippets/js.spec.ts index 778070721..7318d6446 100644 --- a/packages/tasks/src/snippets/js.spec.ts +++ b/packages/tasks/src/snippets/js.spec.ts @@ -1,6 +1,6 @@ import type { InferenceSnippet, ModelDataMinimal } from "./types"; import { describe, expect, it } from "vitest"; -import { snippetTextGeneration } from "./js"; +import { getJsInferenceSnippet } from "./js"; describe("inference API snippets", () => { it("conversational llm", async () => { @@ -10,7 +10,7 @@ describe("inference API snippets", () => { tags: ["conversational"], inference: "", }; - const snippet = snippetTextGeneration(model, "api_token") as InferenceSnippet[]; + const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" @@ -38,6 +38,33 @@ for await (const chunk of stream) { }`); }); + it("conversational llm non-streaming", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = getJsInferenceSnippet(model, "api_token", { streaming: false }) as InferenceSnippet[]; + + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + +const client = new HfInference("api_token") + +const chatCompletion = await client.chatCompletion({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + +console.log(chatCompletion.choices[0].message);`); + }); + it("conversational vlm", async () => { const model: ModelDataMinimal = { id: "meta-llama/Llama-3.2-11B-Vision-Instruct", @@ -45,7 +72,7 @@ for await (const chunk of stream) { tags: ["conversational"], inference: "", }; - const snippet = snippetTextGeneration(model, "api_token") as InferenceSnippet[]; + const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" @@ -75,6 +102,41 @@ const stream = client.chatCompletionStream({ max_tokens: 500 }); +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +}`); + }); + + it("conversational llm", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; + + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + +const client = new HfInference("api_token") + +let out = ""; + +const stream = client.chatCompletionStream({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + for await (const chunk of stream) { if (chunk.choices && chunk.choices.length > 0) { const newContent = chunk.choices[0].delta.content; diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index 5baa7ee85..2728bbf98 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -109,7 +109,7 @@ for await (const chunk of stream) { return [ { client: "huggingface.js", - content: `import { HfInference } from '@huggingface/inference' + content: `import { HfInference } from "@huggingface/inference" const client = new HfInference("${accessToken || `{API_TOKEN}`}") @@ -292,10 +292,11 @@ export const jsSnippets: Partial< export function getJsInferenceSnippet( model: ModelDataMinimal, - accessToken: string + accessToken: string, + opts?: Record ): InferenceSnippet | InferenceSnippet[] { return model.pipeline_tag && model.pipeline_tag in jsSnippets - ? jsSnippets[model.pipeline_tag]?.(model, accessToken) ?? { content: "" } + ? jsSnippets[model.pipeline_tag]?.(model, accessToken, opts) ?? { content: "" } : { content: "" }; } diff --git a/packages/tasks/src/snippets/python.spec.ts b/packages/tasks/src/snippets/python.spec.ts index 3f1ee4979..1e502ea5f 100644 --- a/packages/tasks/src/snippets/python.spec.ts +++ b/packages/tasks/src/snippets/python.spec.ts @@ -1,6 +1,6 @@ -import type { ModelDataMinimal } from "./types"; +import type { InferenceSnippet, ModelDataMinimal } from "./types"; import { describe, expect, it } from "vitest"; -import { snippetConversational } from "./python"; +import { getPythonInferenceSnippet } from "./python"; describe("inference API snippets", () => { it("conversational llm", async () => { @@ -10,7 +10,7 @@ describe("inference API snippets", () => { tags: ["conversational"], inference: "", }; - const snippet = snippetConversational(model, "api_token"); + const snippet = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient @@ -34,6 +34,35 @@ for chunk in stream: print(chunk.choices[0].delta.content, end="")`); }); + it("conversational llm non-streaming", async () => { + const model: ModelDataMinimal = { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = getPythonInferenceSnippet(model, "api_token", { streaming: false }) as InferenceSnippet[]; + + expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +completion = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500 +) + +print(completion.choices[0].message)`); + }); + it("conversational vlm", async () => { const model: ModelDataMinimal = { id: "meta-llama/Llama-3.2-11B-Vision-Instruct", @@ -41,7 +70,7 @@ for chunk in stream: tags: ["conversational"], inference: "", }; - const snippet = snippetConversational(model, "api_token"); + const snippet = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient From f5de41b6445944734dd1f0d5eecc909e667a6312 Mon Sep 17 00:00:00 2001 From: machineuser Date: Thu, 14 Nov 2024 14:18:58 +0000 Subject: [PATCH 34/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index ad7193d93..928ccd7f2 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.0", + "version": "0.13.1", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From a626ee592ed9e7fa2d9a2ce8b14ed1ee52e978cf Mon Sep 17 00:00:00 2001 From: Lucain Date: Thu, 14 Nov 2024 15:33:19 +0100 Subject: [PATCH 35/97] Document python text to image snippets (#1016) Supersedes https://github.com/huggingface/huggingface.js/pull/994. This PR adds an `huggingface_hub` snippet for `text-to-image` inference in Python. I added a test as done in https://github.com/huggingface/huggingface.js/pull/1003. Once this one is approved and merged, I'll move on with all other tasks that the `InferenceClient` supports. --------- Co-authored-by: Mishig --- packages/tasks/src/snippets/python.spec.ts | 37 ++++++++++++++++++++++ packages/tasks/src/snippets/python.ts | 27 +++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/packages/tasks/src/snippets/python.spec.ts b/packages/tasks/src/snippets/python.spec.ts index 1e502ea5f..1bae17cb3 100644 --- a/packages/tasks/src/snippets/python.spec.ts +++ b/packages/tasks/src/snippets/python.spec.ts @@ -104,4 +104,41 @@ stream = client.chat.completions.create( for chunk in stream: print(chunk.choices[0].delta.content, end="")`); }); + + it("text-to-image", async () => { + const model: ModelDataMinimal = { + id: "black-forest-labs/FLUX.1-schnell", + pipeline_tag: "text-to-image", + tags: [], + inference: "", + }; + const snippets = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; + + expect(snippets.length).toEqual(2); + + expect(snippets[0].client).toEqual("huggingface_hub"); + expect(snippets[0].content).toEqual(`from huggingface_hub import InferenceClient +client = InferenceClient("black-forest-labs/FLUX.1-schnell", token="api_token") + +# output is a PIL.Image object +image = client.text_to_image("Astronaut riding a horse")`); + + expect(snippets[1].client).toEqual("requests"); + expect(snippets[1].content).toEqual(`import requests + +API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell" +headers = {"Authorization": "Bearer api_token"} + +def query(payload): + response = requests.post(API_URL, headers=headers, json=payload) + return response.content +image_bytes = query({ + "inputs": "Astronaut riding a horse", +}) + +# You can access the image with PIL.Image for example +import io +from PIL import Image +image = Image.open(io.BytesIO(image_bytes))`); + }); }); diff --git a/packages/tasks/src/snippets/python.ts b/packages/tasks/src/snippets/python.ts index 31ce47a10..bdb148e39 100644 --- a/packages/tasks/src/snippets/python.ts +++ b/packages/tasks/src/snippets/python.ts @@ -4,6 +4,11 @@ import { stringifyGenerationConfig, stringifyMessages } from "./common.js"; import { getModelInputSnippet } from "./inputs.js"; import type { InferenceSnippet, ModelDataMinimal } from "./types.js"; +const snippetImportInferenceClient = (model: ModelDataMinimal, accessToken: string): string => + `from huggingface_hub import InferenceClient +client = InferenceClient("${model.id}", token="${accessToken || "{API_TOKEN}"}") +`; + export const snippetConversational = ( model: ModelDataMinimal, accessToken: string, @@ -161,18 +166,28 @@ export const snippetFile = (model: ModelDataMinimal): InferenceSnippet => ({ output = query(${getModelInputSnippet(model)})`, }); -export const snippetTextToImage = (model: ModelDataMinimal): InferenceSnippet => ({ - content: `def query(payload): +export const snippetTextToImage = (model: ModelDataMinimal, accessToken: string): InferenceSnippet[] => [ + { + client: "huggingface_hub", + content: `${snippetImportInferenceClient(model, accessToken)} +# output is a PIL.Image object +image = client.text_to_image(${getModelInputSnippet(model)})`, + }, + { + client: "requests", + content: `def query(payload): response = requests.post(API_URL, headers=headers, json=payload) return response.content image_bytes = query({ "inputs": ${getModelInputSnippet(model)}, }) + # You can access the image with PIL.Image for example import io from PIL import Image image = Image.open(io.BytesIO(image_bytes))`, -}); + }, +]; export const snippetTabular = (model: ModelDataMinimal): InferenceSnippet => ({ content: `def query(payload): @@ -288,12 +303,14 @@ export function getPythonInferenceSnippet( return snippets.map((snippet) => { return { ...snippet, - content: `import requests + content: snippet.content.includes("requests") + ? `import requests API_URL = "https://api-inference.huggingface.co/models/${model.id}" headers = {"Authorization": ${accessToken ? `"Bearer ${accessToken}"` : `f"Bearer {API_TOKEN}"`}} -${snippet.content}`, +${snippet.content}` + : snippet.content, }; }); } From 06fb21064ada2cd755f9cae670be5c14655a59a3 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Thu, 14 Nov 2024 22:19:21 +0100 Subject: [PATCH 36/97] =?UTF-8?q?=E2=9C=A8=20Switch=20to=20nodenext=20reso?= =?UTF-8?q?lution=20(#1026)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seems necessary for https://github.com/huggingface/huggingface.js/pull/1025 - also handle https://github.com/huggingface/huggingface.js/issues/1001 (only for tasks at the moment) cc @martin-gorner also so that https://arethetypeswrong.github.io/?p=@huggingface/tasks is :heavy_check_mark: cc @Pierrci - in addition to the .cts exports And finally export snippets types (https://github.com/huggingface-internal/moon-landing/pull/10998/files#r1841375306) Types pass: https://arethetypeswrong.github.io/?p=%40huggingface%2Ftasks%400.13.0-test5 ! --- packages/gguf/src/gguf.spec.ts | 2 +- packages/tasks/package.json | 6 +- packages/tasks/scripts/generate-cts.ts | 19 +++ packages/tasks/src/default-widget-inputs.ts | 4 +- packages/tasks/src/index.ts | 42 +++--- packages/tasks/src/library-to-tasks.ts | 4 +- packages/tasks/src/local-apps.ts | 6 +- packages/tasks/src/model-data.ts | 6 +- .../tasks/src/model-libraries-snippets.ts | 6 +- packages/tasks/src/model-libraries.ts | 6 +- packages/tasks/src/snippets/common.ts | 2 +- packages/tasks/src/snippets/curl.spec.ts | 4 +- packages/tasks/src/snippets/index.ts | 9 +- packages/tasks/src/snippets/inputs.ts | 6 +- packages/tasks/src/snippets/js.spec.ts | 4 +- packages/tasks/src/snippets/python.spec.ts | 4 +- packages/tasks/src/snippets/types.ts | 2 +- .../src/tasks/audio-classification/data.ts | 2 +- .../tasks/src/tasks/audio-to-audio/data.ts | 2 +- .../automatic-speech-recognition/data.ts | 2 +- .../tasks/src/tasks/depth-estimation/data.ts | 2 +- .../tasks/document-question-answering/data.ts | 2 +- .../src/tasks/feature-extraction/data.ts | 2 +- packages/tasks/src/tasks/fill-mask/data.ts | 2 +- .../src/tasks/image-classification/data.ts | 2 +- .../tasks/image-feature-extraction/data.ts | 2 +- .../src/tasks/image-segmentation/data.ts | 2 +- .../src/tasks/image-text-to-text/data.ts | 2 +- packages/tasks/src/tasks/image-to-3d/data.ts | 2 +- .../tasks/src/tasks/image-to-image/data.ts | 2 +- .../tasks/src/tasks/image-to-text/data.ts | 2 +- packages/tasks/src/tasks/index.ts | 140 +++++++++--------- .../src/tasks/keypoint-detection/data.ts | 2 +- .../tasks/src/tasks/mask-generation/data.ts | 2 +- .../tasks/src/tasks/object-detection/data.ts | 2 +- packages/tasks/src/tasks/placeholder/data.ts | 2 +- .../src/tasks/question-answering/data.ts | 2 +- .../src/tasks/reinforcement-learning/data.ts | 2 +- .../src/tasks/sentence-similarity/data.ts | 2 +- .../tasks/src/tasks/summarization/data.ts | 2 +- .../tasks/table-question-answering/data.ts | 2 +- .../src/tasks/tabular-classification/data.ts | 2 +- .../src/tasks/tabular-regression/data.ts | 2 +- .../src/tasks/text-classification/data.ts | 2 +- .../tasks/src/tasks/text-generation/data.ts | 2 +- packages/tasks/src/tasks/text-to-3d/data.ts | 2 +- .../tasks/src/tasks/text-to-image/data.ts | 2 +- .../tasks/src/tasks/text-to-speech/data.ts | 2 +- .../tasks/src/tasks/text-to-video/data.ts | 2 +- .../src/tasks/token-classification/data.ts | 2 +- packages/tasks/src/tasks/translation/data.ts | 2 +- .../unconditional-image-generation/data.ts | 2 +- .../src/tasks/video-classification/data.ts | 2 +- .../src/tasks/video-text-to-text/data.ts | 2 +- .../tasks/visual-question-answering/data.ts | 2 +- .../tasks/zero-shot-classification/data.ts | 2 +- .../zero-shot-image-classification/data.ts | 2 +- .../tasks/zero-shot-object-detection/data.ts | 2 +- packages/tasks/src/widget-example.ts | 2 +- packages/tasks/tsconfig.json | 6 +- packages/tasks/tsconfig.local.json | 4 + 61 files changed, 196 insertions(+), 168 deletions(-) create mode 100644 packages/tasks/scripts/generate-cts.ts create mode 100644 packages/tasks/tsconfig.local.json diff --git a/packages/gguf/src/gguf.spec.ts b/packages/gguf/src/gguf.spec.ts index 5e1d08226..58852dbee 100644 --- a/packages/gguf/src/gguf.spec.ts +++ b/packages/gguf/src/gguf.spec.ts @@ -33,7 +33,7 @@ describe("gguf", () => { const arrayBuf = await res.arrayBuffer(); fs.writeFileSync(".cache/model.gguf", Buffer.from(arrayBuf)); } - }); + }, 30_000); it("should parse a llama2 7b", async () => { const { metadata, tensorInfos } = await gguf(URL_LLAMA); diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 928ccd7f2..a05cb18f3 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -9,10 +9,9 @@ }, "main": "./dist/index.cjs", "module": "./dist/index.js", - "types": "./dist/src/index.d.ts", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./dist/src/index.d.ts", "require": "./dist/index.cjs", "import": "./dist/index.js" } @@ -24,13 +23,14 @@ "format": "prettier --write .", "format:check": "prettier --check .", "prepublishOnly": "pnpm run inference-codegen && git diff --name-only --exit-code src && pnpm run build", - "build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly --declaration", + "build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly --declaration && pnpm run generate-cts", "watch:export": "tsup src/index.ts --format cjs,esm --watch", "watch:types": "tsc --emitDeclarationOnly --declaration --watch", "watch": "npm-run-all --parallel watch:export watch:types", "prepare": "pnpm run build", "check": "tsc", "test": "vitest run", + "generate-cts": "tsx scripts/generate-cts.ts", "inference-codegen": "tsx scripts/inference-codegen.ts && prettier --write src/tasks/*/inference.ts", "inference-tgi-import": "tsx scripts/inference-tgi-import.ts && prettier --write src/tasks/text-generation/spec/*.json && prettier --write src/tasks/chat-completion/spec/*.json", "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write src/tasks/feature-extraction/spec/*.json" diff --git a/packages/tasks/scripts/generate-cts.ts b/packages/tasks/scripts/generate-cts.ts new file mode 100644 index 000000000..4c128a984 --- /dev/null +++ b/packages/tasks/scripts/generate-cts.ts @@ -0,0 +1,19 @@ +// Just copy over the already generated .d.ts and .d.ts.map files to .d.cts and .d.cts.map files +import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; + +function recursiveCopy(path: string) { + for (const item of readdirSync(path)) { + if (item.endsWith(".d.ts")) { + const content = readFileSync(join(path, item), "utf-8"); + writeFileSync(join(path, item.replace(".d.ts", ".d.cts")), content.replaceAll(".d.ts.map", ".d.cts.map")); + } else if (item.endsWith(".d.ts.map")) { + const content = readFileSync(join(path, item), "utf-8"); + writeFileSync(join(path, item.replace(".d.ts.map", ".d.cts.map")), content.replaceAll(".d.ts", ".d.cts")); + } else if (statSync(join(path, item)).isDirectory()) { + recursiveCopy(join(path, item)); + } + } +} + +recursiveCopy("dist"); diff --git a/packages/tasks/src/default-widget-inputs.ts b/packages/tasks/src/default-widget-inputs.ts index b0f96ff40..906a0dcc0 100644 --- a/packages/tasks/src/default-widget-inputs.ts +++ b/packages/tasks/src/default-widget-inputs.ts @@ -1,5 +1,5 @@ -import type { WidgetExample } from "./widget-example"; -import type { WidgetType } from "./pipelines"; +import type { WidgetExample } from "./widget-example.js"; +import type { WidgetType } from "./pipelines.js"; type LanguageCode = string; diff --git a/packages/tasks/src/index.ts b/packages/tasks/src/index.ts index e80a9013f..a3f69c2b3 100644 --- a/packages/tasks/src/index.ts +++ b/packages/tasks/src/index.ts @@ -1,7 +1,7 @@ -export { LIBRARY_TASK_MAPPING } from "./library-to-tasks"; -export { MAPPING_DEFAULT_WIDGET } from "./default-widget-inputs"; -export type { TaskData, TaskDemo, TaskDemoEntry, ExampleRepo } from "./tasks"; -export * from "./tasks"; +export { LIBRARY_TASK_MAPPING } from "./library-to-tasks.js"; +export { MAPPING_DEFAULT_WIDGET } from "./default-widget-inputs.js"; +export type { TaskData, TaskDemo, TaskDemoEntry, ExampleRepo } from "./tasks/index.js"; +export * from "./tasks/index.js"; export { PIPELINE_DATA, PIPELINE_TYPES, @@ -13,11 +13,15 @@ export { MODALITY_LABELS, SUBTASK_TYPES, PIPELINE_TYPES_SET, -} from "./pipelines"; -export { ALL_DISPLAY_MODEL_LIBRARY_KEYS, ALL_MODEL_LIBRARY_KEYS, MODEL_LIBRARIES_UI_ELEMENTS } from "./model-libraries"; -export type { LibraryUiElement, ModelLibraryKey } from "./model-libraries"; -export type { ModelData, TransformersInfo } from "./model-data"; -export type { AddedToken, SpecialTokensMap, TokenizerConfig } from "./tokenizer-data"; +} from "./pipelines.js"; +export { + ALL_DISPLAY_MODEL_LIBRARY_KEYS, + ALL_MODEL_LIBRARY_KEYS, + MODEL_LIBRARIES_UI_ELEMENTS, +} from "./model-libraries.js"; +export type { LibraryUiElement, ModelLibraryKey } from "./model-libraries.js"; +export type { ModelData, TransformersInfo } from "./model-data.js"; +export type { AddedToken, SpecialTokensMap, TokenizerConfig } from "./tokenizer-data.js"; export type { WidgetExample, WidgetExampleAttribute, @@ -38,18 +42,18 @@ export type { WidgetExampleOutputLabels, WidgetExampleOutputAnswerScore, WidgetExampleOutputText, -} from "./widget-example"; -export { SPECIAL_TOKENS_ATTRIBUTES } from "./tokenizer-data"; +} from "./widget-example.js"; +export { SPECIAL_TOKENS_ATTRIBUTES } from "./tokenizer-data.js"; -import * as snippets from "./snippets"; -export * from "./gguf"; +import * as snippets from "./snippets/index.js"; +export * from "./gguf.js"; export { snippets }; -export { SKUS, DEFAULT_MEMORY_OPTIONS } from "./hardware"; -export type { HardwareSpec, SkuType } from "./hardware"; -export { LOCAL_APPS } from "./local-apps"; -export type { LocalApp, LocalAppKey, LocalAppSnippet } from "./local-apps"; +export { SKUS, DEFAULT_MEMORY_OPTIONS } from "./hardware.js"; +export type { HardwareSpec, SkuType } from "./hardware.js"; +export { LOCAL_APPS } from "./local-apps.js"; +export type { LocalApp, LocalAppKey, LocalAppSnippet } from "./local-apps.js"; -export { DATASET_LIBRARIES_UI_ELEMENTS } from "./dataset-libraries"; -export type { DatasetLibraryUiElement, DatasetLibraryKey } from "./dataset-libraries"; +export { DATASET_LIBRARIES_UI_ELEMENTS } from "./dataset-libraries.js"; +export type { DatasetLibraryUiElement, DatasetLibraryKey } from "./dataset-libraries.js"; diff --git a/packages/tasks/src/library-to-tasks.ts b/packages/tasks/src/library-to-tasks.ts index c8411fbaa..e3f0f5b60 100644 --- a/packages/tasks/src/library-to-tasks.ts +++ b/packages/tasks/src/library-to-tasks.ts @@ -1,5 +1,5 @@ -import type { ModelLibraryKey } from "./model-libraries"; -import type { PipelineType } from "./pipelines"; +import type { ModelLibraryKey } from "./model-libraries.js"; +import type { PipelineType } from "./pipelines.js"; /** * Mapping from library name to its supported tasks. diff --git a/packages/tasks/src/local-apps.ts b/packages/tasks/src/local-apps.ts index 683b62989..edc7e64fd 100644 --- a/packages/tasks/src/local-apps.ts +++ b/packages/tasks/src/local-apps.ts @@ -1,6 +1,6 @@ -import { parseGGUFQuantLabel } from "./gguf"; -import type { ModelData } from "./model-data"; -import type { PipelineType } from "./pipelines"; +import { parseGGUFQuantLabel } from "./gguf.js"; +import type { ModelData } from "./model-data.js"; +import type { PipelineType } from "./pipelines.js"; export interface LocalAppSnippet { /** diff --git a/packages/tasks/src/model-data.ts b/packages/tasks/src/model-data.ts index 12c8137d9..975517f3a 100644 --- a/packages/tasks/src/model-data.ts +++ b/packages/tasks/src/model-data.ts @@ -1,6 +1,6 @@ -import type { PipelineType } from "./pipelines"; -import type { WidgetExample } from "./widget-example"; -import type { TokenizerConfig } from "./tokenizer-data"; +import type { PipelineType } from "./pipelines.js"; +import type { WidgetExample } from "./widget-example.js"; +import type { TokenizerConfig } from "./tokenizer-data.js"; /** * Public interface for model metadata diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index fa5c87753..523d1a245 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -1,6 +1,6 @@ -import type { ModelData } from "./model-data"; -import type { WidgetExampleTextInput, WidgetExampleSentenceSimilarityInput } from "./widget-example"; -import { LIBRARY_TASK_MAPPING } from "./library-to-tasks"; +import type { ModelData } from "./model-data.js"; +import type { WidgetExampleTextInput, WidgetExampleSentenceSimilarityInput } from "./widget-example.js"; +import { LIBRARY_TASK_MAPPING } from "./library-to-tasks.js"; const TAG_CUSTOM_CODE = "custom_code"; diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 168f1471a..c4bda8222 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -1,6 +1,6 @@ -import * as snippets from "./model-libraries-snippets"; -import type { ModelData } from "./model-data"; -import type { ElasticSearchQuery } from "./model-libraries-downloads"; +import * as snippets from "./model-libraries-snippets.js"; +import type { ModelData } from "./model-data.js"; +import type { ElasticSearchQuery } from "./model-libraries-downloads.js"; /** * Elements configurable by a model library. diff --git a/packages/tasks/src/snippets/common.ts b/packages/tasks/src/snippets/common.ts index 0f82db815..fe5452f69 100644 --- a/packages/tasks/src/snippets/common.ts +++ b/packages/tasks/src/snippets/common.ts @@ -1,4 +1,4 @@ -import type { ChatCompletionInputMessage, GenerationParameters } from "../tasks"; +import type { ChatCompletionInputMessage, GenerationParameters } from "../tasks/index.js"; export function stringifyMessages( messages: ChatCompletionInputMessage[], diff --git a/packages/tasks/src/snippets/curl.spec.ts b/packages/tasks/src/snippets/curl.spec.ts index 19eaf76e3..8c025ca19 100644 --- a/packages/tasks/src/snippets/curl.spec.ts +++ b/packages/tasks/src/snippets/curl.spec.ts @@ -1,6 +1,6 @@ -import type { ModelDataMinimal } from "./types"; +import type { ModelDataMinimal } from "./types.js"; import { describe, expect, it } from "vitest"; -import { getCurlInferenceSnippet } from "./curl"; +import { getCurlInferenceSnippet } from "./curl.js"; describe("inference API snippets", () => { it("conversational llm", async () => { diff --git a/packages/tasks/src/snippets/index.ts b/packages/tasks/src/snippets/index.ts index 3cf9b9d23..c37645815 100644 --- a/packages/tasks/src/snippets/index.ts +++ b/packages/tasks/src/snippets/index.ts @@ -1,6 +1,7 @@ -import * as inputs from "./inputs"; -import * as curl from "./curl"; -import * as python from "./python"; -import * as js from "./js"; +import * as inputs from "./inputs.js"; +import * as curl from "./curl.js"; +import * as python from "./python.js"; +import * as js from "./js.js"; +export * from "./types.js"; export { inputs, curl, python, js }; diff --git a/packages/tasks/src/snippets/inputs.ts b/packages/tasks/src/snippets/inputs.ts index 70afde388..49e270dff 100644 --- a/packages/tasks/src/snippets/inputs.ts +++ b/packages/tasks/src/snippets/inputs.ts @@ -1,6 +1,6 @@ -import type { PipelineType } from "../pipelines"; -import type { ChatCompletionInputMessage } from "../tasks"; -import type { ModelDataMinimal } from "./types"; +import type { PipelineType } from "../pipelines.js"; +import type { ChatCompletionInputMessage } from "../tasks/index.js"; +import type { ModelDataMinimal } from "./types.js"; const inputsZeroShotClassification = () => `"Hi, I recently bought a device from your company but it is not working as advertised and I would like to get reimbursed!"`; diff --git a/packages/tasks/src/snippets/js.spec.ts b/packages/tasks/src/snippets/js.spec.ts index 7318d6446..644f9a548 100644 --- a/packages/tasks/src/snippets/js.spec.ts +++ b/packages/tasks/src/snippets/js.spec.ts @@ -1,6 +1,6 @@ -import type { InferenceSnippet, ModelDataMinimal } from "./types"; +import type { InferenceSnippet, ModelDataMinimal } from "./types.js"; import { describe, expect, it } from "vitest"; -import { getJsInferenceSnippet } from "./js"; +import { getJsInferenceSnippet } from "./js.js"; describe("inference API snippets", () => { it("conversational llm", async () => { diff --git a/packages/tasks/src/snippets/python.spec.ts b/packages/tasks/src/snippets/python.spec.ts index 1bae17cb3..01ab4fcf4 100644 --- a/packages/tasks/src/snippets/python.spec.ts +++ b/packages/tasks/src/snippets/python.spec.ts @@ -1,6 +1,6 @@ -import type { InferenceSnippet, ModelDataMinimal } from "./types"; +import type { InferenceSnippet, ModelDataMinimal } from "./types.js"; import { describe, expect, it } from "vitest"; -import { getPythonInferenceSnippet } from "./python"; +import { getPythonInferenceSnippet } from "./python.js"; describe("inference API snippets", () => { it("conversational llm", async () => { diff --git a/packages/tasks/src/snippets/types.ts b/packages/tasks/src/snippets/types.ts index 230fdc9b8..c6a78c278 100644 --- a/packages/tasks/src/snippets/types.ts +++ b/packages/tasks/src/snippets/types.ts @@ -1,4 +1,4 @@ -import type { ModelData } from "../model-data"; +import type { ModelData } from "../model-data.js"; /** * Minimal model data required for snippets. diff --git a/packages/tasks/src/tasks/audio-classification/data.ts b/packages/tasks/src/tasks/audio-classification/data.ts index be123d341..8919f81c0 100644 --- a/packages/tasks/src/tasks/audio-classification/data.ts +++ b/packages/tasks/src/tasks/audio-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/audio-to-audio/data.ts b/packages/tasks/src/tasks/audio-to-audio/data.ts index 9d92983b2..fa1c3a508 100644 --- a/packages/tasks/src/tasks/audio-to-audio/data.ts +++ b/packages/tasks/src/tasks/audio-to-audio/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/automatic-speech-recognition/data.ts b/packages/tasks/src/tasks/automatic-speech-recognition/data.ts index 89078ce71..323c6fab3 100644 --- a/packages/tasks/src/tasks/automatic-speech-recognition/data.ts +++ b/packages/tasks/src/tasks/automatic-speech-recognition/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/depth-estimation/data.ts b/packages/tasks/src/tasks/depth-estimation/data.ts index 735f1ccb5..390449149 100644 --- a/packages/tasks/src/tasks/depth-estimation/data.ts +++ b/packages/tasks/src/tasks/depth-estimation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/document-question-answering/data.ts b/packages/tasks/src/tasks/document-question-answering/data.ts index f36ed212c..d40cfe613 100644 --- a/packages/tasks/src/tasks/document-question-answering/data.ts +++ b/packages/tasks/src/tasks/document-question-answering/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/feature-extraction/data.ts b/packages/tasks/src/tasks/feature-extraction/data.ts index 8bf923349..75f5d6f5e 100644 --- a/packages/tasks/src/tasks/feature-extraction/data.ts +++ b/packages/tasks/src/tasks/feature-extraction/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/fill-mask/data.ts b/packages/tasks/src/tasks/fill-mask/data.ts index 55550f042..1ed7849f1 100644 --- a/packages/tasks/src/tasks/fill-mask/data.ts +++ b/packages/tasks/src/tasks/fill-mask/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-classification/data.ts b/packages/tasks/src/tasks/image-classification/data.ts index 875b19742..a4cd9fd42 100644 --- a/packages/tasks/src/tasks/image-classification/data.ts +++ b/packages/tasks/src/tasks/image-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-feature-extraction/data.ts b/packages/tasks/src/tasks/image-feature-extraction/data.ts index 71861204e..8880d5bf8 100644 --- a/packages/tasks/src/tasks/image-feature-extraction/data.ts +++ b/packages/tasks/src/tasks/image-feature-extraction/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-segmentation/data.ts b/packages/tasks/src/tasks/image-segmentation/data.ts index 5469a30d2..555e5db3e 100644 --- a/packages/tasks/src/tasks/image-segmentation/data.ts +++ b/packages/tasks/src/tasks/image-segmentation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-text-to-text/data.ts b/packages/tasks/src/tasks/image-text-to-text/data.ts index e096f0195..e77ffc68f 100644 --- a/packages/tasks/src/tasks/image-text-to-text/data.ts +++ b/packages/tasks/src/tasks/image-text-to-text/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-to-3d/data.ts b/packages/tasks/src/tasks/image-to-3d/data.ts index e9dd93651..6556e1b02 100644 --- a/packages/tasks/src/tasks/image-to-3d/data.ts +++ b/packages/tasks/src/tasks/image-to-3d/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-to-image/data.ts b/packages/tasks/src/tasks/image-to-image/data.ts index a08c19edd..fa2ddc248 100644 --- a/packages/tasks/src/tasks/image-to-image/data.ts +++ b/packages/tasks/src/tasks/image-to-image/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/image-to-text/data.ts b/packages/tasks/src/tasks/image-to-text/data.ts index 64f4fe5c8..a269d9497 100644 --- a/packages/tasks/src/tasks/image-to-text/data.ts +++ b/packages/tasks/src/tasks/image-to-text/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/index.ts b/packages/tasks/src/tasks/index.ts index 3e9a02663..7392cfa91 100644 --- a/packages/tasks/src/tasks/index.ts +++ b/packages/tasks/src/tasks/index.ts @@ -1,49 +1,49 @@ -import type { PipelineType } from "../pipelines"; -import { PIPELINE_DATA } from "../pipelines"; +import type { PipelineType } from "../pipelines.js"; +import { PIPELINE_DATA } from "../pipelines.js"; -import audioClassification from "./audio-classification/data"; -import audioToAudio from "./audio-to-audio/data"; -import automaticSpeechRecognition from "./automatic-speech-recognition/data"; -import documentQuestionAnswering from "./document-question-answering/data"; -import featureExtraction from "./feature-extraction/data"; -import fillMask from "./fill-mask/data"; -import imageClassification from "./image-classification/data"; -import imageFeatureExtraction from "./image-feature-extraction/data"; -import imageToImage from "./image-to-image/data"; -import imageToText from "./image-to-text/data"; -import imageTextToText from "./image-text-to-text/data"; -import imageSegmentation from "./image-segmentation/data"; -import maskGeneration from "./mask-generation/data"; -import objectDetection from "./object-detection/data"; -import depthEstimation from "./depth-estimation/data"; -import placeholder from "./placeholder/data"; -import reinforcementLearning from "./reinforcement-learning/data"; -import questionAnswering from "./question-answering/data"; -import sentenceSimilarity from "./sentence-similarity/data"; -import summarization from "./summarization/data"; -import tableQuestionAnswering from "./table-question-answering/data"; -import tabularClassification from "./tabular-classification/data"; -import tabularRegression from "./tabular-regression/data"; -import textToImage from "./text-to-image/data"; -import textToSpeech from "./text-to-speech/data"; -import tokenClassification from "./token-classification/data"; -import translation from "./translation/data"; -import textClassification from "./text-classification/data"; -import textGeneration from "./text-generation/data"; -import textToVideo from "./text-to-video/data"; -import unconditionalImageGeneration from "./unconditional-image-generation/data"; -import videoClassification from "./video-classification/data"; -import visualQuestionAnswering from "./visual-question-answering/data"; -import zeroShotClassification from "./zero-shot-classification/data"; -import zeroShotImageClassification from "./zero-shot-image-classification/data"; -import zeroShotObjectDetection from "./zero-shot-object-detection/data"; -import imageTo3D from "./image-to-3d/data"; -import textTo3D from "./text-to-3d/data"; -import keypointDetection from "./keypoint-detection/data"; -import videoTextToText from "./video-text-to-text/data"; +import audioClassification from "./audio-classification/data.js"; +import audioToAudio from "./audio-to-audio/data.js"; +import automaticSpeechRecognition from "./automatic-speech-recognition/data.js"; +import documentQuestionAnswering from "./document-question-answering/data.js"; +import featureExtraction from "./feature-extraction/data.js"; +import fillMask from "./fill-mask/data.js"; +import imageClassification from "./image-classification/data.js"; +import imageFeatureExtraction from "./image-feature-extraction/data.js"; +import imageToImage from "./image-to-image/data.js"; +import imageToText from "./image-to-text/data.js"; +import imageTextToText from "./image-text-to-text/data.js"; +import imageSegmentation from "./image-segmentation/data.js"; +import maskGeneration from "./mask-generation/data.js"; +import objectDetection from "./object-detection/data.js"; +import depthEstimation from "./depth-estimation/data.js"; +import placeholder from "./placeholder/data.js"; +import reinforcementLearning from "./reinforcement-learning/data.js"; +import questionAnswering from "./question-answering/data.js"; +import sentenceSimilarity from "./sentence-similarity/data.js"; +import summarization from "./summarization/data.js"; +import tableQuestionAnswering from "./table-question-answering/data.js"; +import tabularClassification from "./tabular-classification/data.js"; +import tabularRegression from "./tabular-regression/data.js"; +import textToImage from "./text-to-image/data.js"; +import textToSpeech from "./text-to-speech/data.js"; +import tokenClassification from "./token-classification/data.js"; +import translation from "./translation/data.js"; +import textClassification from "./text-classification/data.js"; +import textGeneration from "./text-generation/data.js"; +import textToVideo from "./text-to-video/data.js"; +import unconditionalImageGeneration from "./unconditional-image-generation/data.js"; +import videoClassification from "./video-classification/data.js"; +import visualQuestionAnswering from "./visual-question-answering/data.js"; +import zeroShotClassification from "./zero-shot-classification/data.js"; +import zeroShotImageClassification from "./zero-shot-image-classification/data.js"; +import zeroShotObjectDetection from "./zero-shot-object-detection/data.js"; +import imageTo3D from "./image-to-3d/data.js"; +import textTo3D from "./text-to-3d/data.js"; +import keypointDetection from "./keypoint-detection/data.js"; +import videoTextToText from "./video-text-to-text/data.js"; -export type * from "./audio-classification/inference"; -export type * from "./automatic-speech-recognition/inference"; +export type * from "./audio-classification/inference.js"; +export type * from "./automatic-speech-recognition/inference.js"; export type { ChatCompletionInput, ChatCompletionInputMessage, @@ -53,36 +53,36 @@ export type { ChatCompletionStreamOutput, ChatCompletionStreamOutputChoice, ChatCompletionStreamOutputDelta, -} from "./chat-completion/inference"; -export type * from "./document-question-answering/inference"; -export type * from "./feature-extraction/inference"; -export type * from "./fill-mask/inference"; +} from "./chat-completion/inference.js"; +export type * from "./document-question-answering/inference.js"; +export type * from "./feature-extraction/inference.js"; +export type * from "./fill-mask/inference.js"; export type { ImageClassificationInput, ImageClassificationOutput, ImageClassificationOutputElement, ImageClassificationParameters, -} from "./image-classification/inference"; -export type * from "./image-to-image/inference"; -export type { ImageToTextInput, ImageToTextOutput, ImageToTextParameters } from "./image-to-text/inference"; -export type * from "./image-segmentation/inference"; -export type * from "./object-detection/inference"; -export type * from "./depth-estimation/inference"; -export type * from "./question-answering/inference"; -export type * from "./sentence-similarity/inference"; -export type * from "./summarization/inference"; -export type * from "./table-question-answering/inference"; -export type { TextToImageInput, TextToImageOutput, TextToImageParameters } from "./text-to-image/inference"; -export type { TextToSpeechParameters, TextToSpeechInput, TextToSpeechOutput } from "./text-to-speech/inference"; -export type * from "./token-classification/inference"; -export type { TranslationInput, TranslationOutput } from "./translation/inference"; +} from "./image-classification/inference.js"; +export type * from "./image-to-image/inference.js"; +export type { ImageToTextInput, ImageToTextOutput, ImageToTextParameters } from "./image-to-text/inference.js"; +export type * from "./image-segmentation/inference.js"; +export type * from "./object-detection/inference.js"; +export type * from "./depth-estimation/inference.js"; +export type * from "./question-answering/inference.js"; +export type * from "./sentence-similarity/inference.js"; +export type * from "./summarization/inference.js"; +export type * from "./table-question-answering/inference.js"; +export type { TextToImageInput, TextToImageOutput, TextToImageParameters } from "./text-to-image/inference.js"; +export type { TextToSpeechParameters, TextToSpeechInput, TextToSpeechOutput } from "./text-to-speech/inference.js"; +export type * from "./token-classification/inference.js"; +export type { TranslationInput, TranslationOutput } from "./translation/inference.js"; export type { ClassificationOutputTransform, TextClassificationInput, TextClassificationOutput, TextClassificationOutputElement, TextClassificationParameters, -} from "./text-classification/inference"; +} from "./text-classification/inference.js"; export type { TextGenerationOutputFinishReason, TextGenerationOutputPrefillToken, @@ -94,20 +94,20 @@ export type { TextGenerationOutputToken, TextGenerationStreamOutputStreamDetails, TextGenerationStreamOutput, -} from "./text-generation/inference"; -export type * from "./video-classification/inference"; -export type * from "./visual-question-answering/inference"; -export type * from "./zero-shot-classification/inference"; -export type * from "./zero-shot-image-classification/inference"; +} from "./text-generation/inference.js"; +export type * from "./video-classification/inference.js"; +export type * from "./visual-question-answering/inference.js"; +export type * from "./zero-shot-classification/inference.js"; +export type * from "./zero-shot-image-classification/inference.js"; export type { BoundingBox, ZeroShotObjectDetectionInput, ZeroShotObjectDetectionInputData, ZeroShotObjectDetectionOutput, ZeroShotObjectDetectionOutputElement, -} from "./zero-shot-object-detection/inference"; +} from "./zero-shot-object-detection/inference.js"; -import type { ModelLibraryKey } from "../model-libraries"; +import type { ModelLibraryKey } from "../model-libraries.js"; /** * Model libraries compatible with each ML task diff --git a/packages/tasks/src/tasks/keypoint-detection/data.ts b/packages/tasks/src/tasks/keypoint-detection/data.ts index 194e48d48..e65b805ba 100644 --- a/packages/tasks/src/tasks/keypoint-detection/data.ts +++ b/packages/tasks/src/tasks/keypoint-detection/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/mask-generation/data.ts b/packages/tasks/src/tasks/mask-generation/data.ts index 6b18b2dbf..133e9a7f6 100644 --- a/packages/tasks/src/tasks/mask-generation/data.ts +++ b/packages/tasks/src/tasks/mask-generation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [], diff --git a/packages/tasks/src/tasks/object-detection/data.ts b/packages/tasks/src/tasks/object-detection/data.ts index 840f7a431..2b1a8a4a9 100644 --- a/packages/tasks/src/tasks/object-detection/data.ts +++ b/packages/tasks/src/tasks/object-detection/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/placeholder/data.ts b/packages/tasks/src/tasks/placeholder/data.ts index 110b43703..5fc9bbb8f 100644 --- a/packages/tasks/src/tasks/placeholder/data.ts +++ b/packages/tasks/src/tasks/placeholder/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [], diff --git a/packages/tasks/src/tasks/question-answering/data.ts b/packages/tasks/src/tasks/question-answering/data.ts index ac1443adf..cf75dd3d7 100644 --- a/packages/tasks/src/tasks/question-answering/data.ts +++ b/packages/tasks/src/tasks/question-answering/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/reinforcement-learning/data.ts b/packages/tasks/src/tasks/reinforcement-learning/data.ts index 71290d677..231ecabda 100644 --- a/packages/tasks/src/tasks/reinforcement-learning/data.ts +++ b/packages/tasks/src/tasks/reinforcement-learning/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/sentence-similarity/data.ts b/packages/tasks/src/tasks/sentence-similarity/data.ts index 3ef54bbd3..ff6b877a0 100644 --- a/packages/tasks/src/tasks/sentence-similarity/data.ts +++ b/packages/tasks/src/tasks/sentence-similarity/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/summarization/data.ts b/packages/tasks/src/tasks/summarization/data.ts index 239a04fc4..de7eb4e4c 100644 --- a/packages/tasks/src/tasks/summarization/data.ts +++ b/packages/tasks/src/tasks/summarization/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { canonicalId: "text2text-generation", diff --git a/packages/tasks/src/tasks/table-question-answering/data.ts b/packages/tasks/src/tasks/table-question-answering/data.ts index 7a4691146..b5f161a4c 100644 --- a/packages/tasks/src/tasks/table-question-answering/data.ts +++ b/packages/tasks/src/tasks/table-question-answering/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/tabular-classification/data.ts b/packages/tasks/src/tasks/tabular-classification/data.ts index c7284cc50..80dbe57d2 100644 --- a/packages/tasks/src/tasks/tabular-classification/data.ts +++ b/packages/tasks/src/tasks/tabular-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/tabular-regression/data.ts b/packages/tasks/src/tasks/tabular-regression/data.ts index d4f085d24..c4c0b6d01 100644 --- a/packages/tasks/src/tasks/tabular-regression/data.ts +++ b/packages/tasks/src/tasks/tabular-regression/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/text-classification/data.ts b/packages/tasks/src/tasks/text-classification/data.ts index b6a26dcc4..5ba1506e9 100644 --- a/packages/tasks/src/tasks/text-classification/data.ts +++ b/packages/tasks/src/tasks/text-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/text-generation/data.ts b/packages/tasks/src/tasks/text-generation/data.ts index ce2240bde..3b783161f 100644 --- a/packages/tasks/src/tasks/text-generation/data.ts +++ b/packages/tasks/src/tasks/text-generation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/text-to-3d/data.ts b/packages/tasks/src/tasks/text-to-3d/data.ts index e66a21275..30f3aefc4 100644 --- a/packages/tasks/src/tasks/text-to-3d/data.ts +++ b/packages/tasks/src/tasks/text-to-3d/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/text-to-image/data.ts b/packages/tasks/src/tasks/text-to-image/data.ts index 82d5473e7..ebf1347d3 100644 --- a/packages/tasks/src/tasks/text-to-image/data.ts +++ b/packages/tasks/src/tasks/text-to-image/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/text-to-speech/data.ts b/packages/tasks/src/tasks/text-to-speech/data.ts index 464a39afc..afa7471cf 100644 --- a/packages/tasks/src/tasks/text-to-speech/data.ts +++ b/packages/tasks/src/tasks/text-to-speech/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { canonicalId: "text-to-audio", diff --git a/packages/tasks/src/tasks/text-to-video/data.ts b/packages/tasks/src/tasks/text-to-video/data.ts index 27f4925ba..ad9867de2 100644 --- a/packages/tasks/src/tasks/text-to-video/data.ts +++ b/packages/tasks/src/tasks/text-to-video/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/token-classification/data.ts b/packages/tasks/src/tasks/token-classification/data.ts index 7a1d1abed..2ecce1bcc 100644 --- a/packages/tasks/src/tasks/token-classification/data.ts +++ b/packages/tasks/src/tasks/token-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/translation/data.ts b/packages/tasks/src/tasks/translation/data.ts index 9707734d9..535f9a84c 100644 --- a/packages/tasks/src/tasks/translation/data.ts +++ b/packages/tasks/src/tasks/translation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { canonicalId: "text2text-generation", diff --git a/packages/tasks/src/tasks/unconditional-image-generation/data.ts b/packages/tasks/src/tasks/unconditional-image-generation/data.ts index 8cbf8a016..fcd66648e 100644 --- a/packages/tasks/src/tasks/unconditional-image-generation/data.ts +++ b/packages/tasks/src/tasks/unconditional-image-generation/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/video-classification/data.ts b/packages/tasks/src/tasks/video-classification/data.ts index 47d2c2d75..1e5abbce9 100644 --- a/packages/tasks/src/tasks/video-classification/data.ts +++ b/packages/tasks/src/tasks/video-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/video-text-to-text/data.ts b/packages/tasks/src/tasks/video-text-to-text/data.ts index eed4add06..bca190bc5 100644 --- a/packages/tasks/src/tasks/video-text-to-text/data.ts +++ b/packages/tasks/src/tasks/video-text-to-text/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/visual-question-answering/data.ts b/packages/tasks/src/tasks/visual-question-answering/data.ts index f31334330..51de32a80 100644 --- a/packages/tasks/src/tasks/visual-question-answering/data.ts +++ b/packages/tasks/src/tasks/visual-question-answering/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/zero-shot-classification/data.ts b/packages/tasks/src/tasks/zero-shot-classification/data.ts index 1ecc51c95..516efa4d1 100644 --- a/packages/tasks/src/tasks/zero-shot-classification/data.ts +++ b/packages/tasks/src/tasks/zero-shot-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/zero-shot-image-classification/data.ts b/packages/tasks/src/tasks/zero-shot-image-classification/data.ts index 5be19aedf..776a6d194 100644 --- a/packages/tasks/src/tasks/zero-shot-image-classification/data.ts +++ b/packages/tasks/src/tasks/zero-shot-image-classification/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [ diff --git a/packages/tasks/src/tasks/zero-shot-object-detection/data.ts b/packages/tasks/src/tasks/zero-shot-object-detection/data.ts index 9e36cad46..6446704d4 100644 --- a/packages/tasks/src/tasks/zero-shot-object-detection/data.ts +++ b/packages/tasks/src/tasks/zero-shot-object-detection/data.ts @@ -1,4 +1,4 @@ -import type { TaskDataCustom } from ".."; +import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { datasets: [], diff --git a/packages/tasks/src/widget-example.ts b/packages/tasks/src/widget-example.ts index 3c47530f4..780953bca 100644 --- a/packages/tasks/src/widget-example.ts +++ b/packages/tasks/src/widget-example.ts @@ -2,7 +2,7 @@ * See default-widget-inputs.ts for the default widget inputs, this files only contains the types */ -import type { ChatCompletionInputMessage } from "./tasks"; +import type { ChatCompletionInputMessage } from "./tasks/index.js"; type TableData = Record; diff --git a/packages/tasks/tsconfig.json b/packages/tasks/tsconfig.json index 6a2bad758..3e3c571e5 100644 --- a/packages/tasks/tsconfig.json +++ b/packages/tasks/tsconfig.json @@ -2,9 +2,9 @@ "compilerOptions": { "allowSyntheticDefaultImports": true, "lib": ["ES2022", "DOM"], - "module": "ESNext", + "module": "NodeNext", "target": "ESNext", - "moduleResolution": "node", + "moduleResolution": "nodenext", "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitAny": true, @@ -15,6 +15,6 @@ "declaration": true, "declarationMap": true }, - "include": ["src", "scripts"], + "include": ["src"], "exclude": ["dist"] } diff --git a/packages/tasks/tsconfig.local.json b/packages/tasks/tsconfig.local.json new file mode 100644 index 000000000..aefb17827 --- /dev/null +++ b/packages/tasks/tsconfig.local.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src", "scripts"] +} From f193bc60cee28d3b5a461e9aa410b2befa7a8f6e Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Fri, 15 Nov 2024 02:03:26 +0100 Subject: [PATCH 37/97] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20Use=20`tshy`=20inste?= =?UTF-8?q?ad=20of=20`tsup`=20for=20releasing=20tasks=20(#1029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up to https://github.com/huggingface/huggingface.js/pull/1026 Benefit is that exports are better defined, and source-mapping works. Also, move the generation scripts from `@huggingace/tasks` to `@huggingface/tasks-gen` cc @Wauplin @SBrandeis So that the dev dependencies are not tacked on `@huggingface/tasks`. Some package managers, *cough* yarn *cough* like to download them when importing a package, even if they're irrelevant. --- .github/workflows/test.yml | 2 +- package.json | 1 + packages/tasks-gen/package.json | 26 ++ packages/tasks-gen/pnpm-lock.yaml | 223 +++++++++++++++++ .../scripts/inference-codegen.ts | 6 +- .../scripts/inference-tei-import.ts | 2 +- .../scripts/inference-tgi-import.ts | 2 +- packages/tasks/.tshy/build.json | 8 + packages/tasks/.tshy/commonjs.json | 16 ++ packages/tasks/.tshy/esm.json | 15 ++ packages/tasks/package.json | 46 ++-- packages/tasks/pnpm-lock.yaml | 217 ---------------- packages/tasks/scripts/generate-cts.ts | 19 -- packages/tasks/tsconfig.local.json | 4 - pnpm-lock.yaml | 236 ++++++++++++++++++ pnpm-workspace.yaml | 1 + 16 files changed, 557 insertions(+), 267 deletions(-) create mode 100644 packages/tasks-gen/package.json create mode 100644 packages/tasks-gen/pnpm-lock.yaml rename packages/{tasks => tasks-gen}/scripts/inference-codegen.ts (98%) rename packages/{tasks => tasks-gen}/scripts/inference-tei-import.ts (98%) rename packages/{tasks => tasks-gen}/scripts/inference-tgi-import.ts (98%) create mode 100644 packages/tasks/.tshy/build.json create mode 100644 packages/tasks/.tshy/commonjs.json create mode 100644 packages/tasks/.tshy/esm.json delete mode 100644 packages/tasks/scripts/generate-cts.ts delete mode 100644 packages/tasks/tsconfig.local.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 99fa2469d..28a657d82 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -104,7 +104,7 @@ jobs: working-directory: e2e run: | sleep 3 - pnpm i --filter root --filter inference... --filter hub... --frozen-lockfile + pnpm i --filter root --filter inference... --filter hub... --filter tasks-gen --frozen-lockfile pnpm --filter inference --filter hub --filter tasks publish --force --no-git-checks --registry http://localhost:4874/ - name: E2E test - test yarn install diff --git a/package.json b/package.json index 3c54eda46..687477c39 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.2", "semver": "^7.5.0", + "tshy": "^3.0.2", "tsup": "^6.7.0", "tsx": "^4.7.0", "typescript": "^5.4.2", diff --git a/packages/tasks-gen/package.json b/packages/tasks-gen/package.json new file mode 100644 index 000000000..2d74c82a0 --- /dev/null +++ b/packages/tasks-gen/package.json @@ -0,0 +1,26 @@ +{ + "name": "@huggingface/tasks-gen", + "packageManager": "pnpm@8.10.5", + "version": "0.13.1", + "description": "Utilities to generate files for @huggingface/tasks, and avoid unnecessary deps in the published package", + "repository": "https://github.com/huggingface/huggingface.js.git", + "private": true, + "scripts": { + "lint": "eslint --quiet --fix --ext .cjs,.ts .", + "lint:check": "eslint --ext .cjs,.ts .", + "format": "prettier --write .", + "format:check": "prettier --check .", + "check": "tsc", + "inference-codegen": "tsx scripts/inference-codegen.ts && prettier --write ../tasks/src/tasks/*/inference.ts", + "inference-tgi-import": "tsx scripts/inference-tgi-import.ts && prettier --write ../tasks/src/tasks/text-generation/spec/*.json && prettier --write ../tasks/src/tasks/chat-completion/spec/*.json", + "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write ../tasks/src/tasks/feature-extraction/spec/*.json" + }, + "type": "module", + "author": "Hugging Face", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.11.5", + "quicktype-core": "https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz", + "type-fest": "^3.13.1" + } +} diff --git a/packages/tasks-gen/pnpm-lock.yaml b/packages/tasks-gen/pnpm-lock.yaml new file mode 100644 index 000000000..f8534970c --- /dev/null +++ b/packages/tasks-gen/pnpm-lock.yaml @@ -0,0 +1,223 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +devDependencies: + '@types/node': + specifier: ^20.11.5 + version: 20.17.6 + quicktype-core: + specifier: https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz + version: '@github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz' + type-fest: + specifier: ^3.13.1 + version: 3.13.1 + +packages: + + /@glideapps/ts-necessities@2.1.3: + resolution: {integrity: sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==} + dev: true + + /@types/node@20.17.6: + resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} + dependencies: + undici-types: 6.19.8 + dev: true + + /@types/urijs@1.19.25: + resolution: {integrity: sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==} + dev: true + + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /browser-or-node@2.1.1: + resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /collection-utils@1.0.1: + resolution: {integrity: sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==} + dev: true + + /cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: true + + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: true + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /is-url@1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + dev: true + + /js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + dev: true + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + + /pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /readable-stream@4.4.2: + resolution: {integrity: sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + dev: true + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: true + + /undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + dev: true + + /unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + dev: true + + /unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + dev: true + + /urijs@1.19.11: + resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true + + /yaml@2.6.0: + resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + engines: {node: '>= 14'} + hasBin: true + dev: true + + '@github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz': + resolution: {tarball: https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz} + name: quicktype-core + version: 18.0.17 + dependencies: + '@glideapps/ts-necessities': 2.1.3 + '@types/urijs': 1.19.25 + browser-or-node: 2.1.1 + collection-utils: 1.0.1 + cross-fetch: 4.0.0 + is-url: 1.2.4 + js-base64: 3.7.7 + lodash: 4.17.21 + pako: 1.0.11 + pluralize: 8.0.0 + readable-stream: 4.4.2 + unicode-properties: 1.4.1 + urijs: 1.19.11 + wordwrap: 1.0.0 + yaml: 2.6.0 + transitivePeerDependencies: + - encoding + dev: true diff --git a/packages/tasks/scripts/inference-codegen.ts b/packages/tasks-gen/scripts/inference-codegen.ts similarity index 98% rename from packages/tasks/scripts/inference-codegen.ts rename to packages/tasks-gen/scripts/inference-codegen.ts index 68d071e57..2b5375119 100644 --- a/packages/tasks/scripts/inference-codegen.ts +++ b/packages/tasks-gen/scripts/inference-codegen.ts @@ -22,8 +22,6 @@ const PYTHON_HEADER_FILE = ` # - specs: https://github.com/huggingface/huggingface.js/tree/main/packages/tasks/src/tasks. `; -const PYTHON_DIR = "./.python_generated"; - const rootDirFinder = function (): string { let currentPath = path.normalize(import.meta.url); @@ -172,8 +170,10 @@ async function postProcessOutput(path2generated: string, outputSpec: Record entry.isDirectory()) diff --git a/packages/tasks/scripts/inference-tei-import.ts b/packages/tasks-gen/scripts/inference-tei-import.ts similarity index 98% rename from packages/tasks/scripts/inference-tei-import.ts rename to packages/tasks-gen/scripts/inference-tei-import.ts index 2765294a7..c7af79547 100644 --- a/packages/tasks/scripts/inference-tei-import.ts +++ b/packages/tasks-gen/scripts/inference-tei-import.ts @@ -24,7 +24,7 @@ const rootDirFinder = function (): string { return "/"; }; -const rootDir = rootDirFinder(); +const rootDir = path.join(rootDirFinder(), "..", "tasks"); const tasksDir = path.join(rootDir, "src", "tasks"); function toCamelCase(str: string, joiner = "") { diff --git a/packages/tasks/scripts/inference-tgi-import.ts b/packages/tasks-gen/scripts/inference-tgi-import.ts similarity index 98% rename from packages/tasks/scripts/inference-tgi-import.ts rename to packages/tasks-gen/scripts/inference-tgi-import.ts index 852d1dc53..27060fd82 100644 --- a/packages/tasks/scripts/inference-tgi-import.ts +++ b/packages/tasks-gen/scripts/inference-tgi-import.ts @@ -24,7 +24,7 @@ const rootDirFinder = function (): string { return "/"; }; -const rootDir = rootDirFinder(); +const rootDir = path.join(rootDirFinder(), "..", "tasks"); const tasksDir = path.join(rootDir, "src", "tasks"); function toCamelCase(str: string, joiner = "") { diff --git a/packages/tasks/.tshy/build.json b/packages/tasks/.tshy/build.json new file mode 100644 index 000000000..aea1a9e93 --- /dev/null +++ b/packages/tasks/.tshy/build.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "../src", + "module": "nodenext", + "moduleResolution": "nodenext" + } +} diff --git a/packages/tasks/.tshy/commonjs.json b/packages/tasks/.tshy/commonjs.json new file mode 100644 index 000000000..7c9db50b6 --- /dev/null +++ b/packages/tasks/.tshy/commonjs.json @@ -0,0 +1,16 @@ +{ + "extends": "./build.json", + "include": [ + "../src/**/*.ts", + "../src/**/*.cts", + "../src/**/*.tsx", + "../src/**/*.json" + ], + "exclude": [ + "../src/**/*.mts", + "../src/package.json" + ], + "compilerOptions": { + "outDir": "../.tshy-build/commonjs" + } +} diff --git a/packages/tasks/.tshy/esm.json b/packages/tasks/.tshy/esm.json new file mode 100644 index 000000000..959294a84 --- /dev/null +++ b/packages/tasks/.tshy/esm.json @@ -0,0 +1,15 @@ +{ + "extends": "./build.json", + "include": [ + "../src/**/*.ts", + "../src/**/*.mts", + "../src/**/*.tsx", + "../src/**/*.json" + ], + "exclude": [ + "../src/package.json" + ], + "compilerOptions": { + "outDir": "../.tshy-build/esm" + } +} diff --git a/packages/tasks/package.json b/packages/tasks/package.json index a05cb18f3..8f2114ab2 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -7,33 +7,33 @@ "publishConfig": { "access": "public" }, - "main": "./dist/index.cjs", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", "exports": { + "./package.json": "./package.json", ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } } }, - "source": "src/index.ts", + "source": "./src/index.ts", "scripts": { "lint": "eslint --quiet --fix --ext .cjs,.ts .", "lint:check": "eslint --ext .cjs,.ts .", "format": "prettier --write .", "format:check": "prettier --check .", - "prepublishOnly": "pnpm run inference-codegen && git diff --name-only --exit-code src && pnpm run build", - "build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly --declaration && pnpm run generate-cts", - "watch:export": "tsup src/index.ts --format cjs,esm --watch", - "watch:types": "tsc --emitDeclarationOnly --declaration --watch", - "watch": "npm-run-all --parallel watch:export watch:types", + "prepublishOnly": "pnpm --filter tasks-gen inference-codegen && git diff --name-only --exit-code src && pnpm run build", + "build": "tshy", + "watch:cjs": "tsc --declaration --outdir dist/commonjs --module commonjs --watch", + "watch:esm": "tsc --declaration --outdir dist/esm --watch", + "watch": "npm-run-all --parallel watch:esm watch:cjs", "prepare": "pnpm run build", "check": "tsc", - "test": "vitest run", - "generate-cts": "tsx scripts/generate-cts.ts", - "inference-codegen": "tsx scripts/inference-codegen.ts && prettier --write src/tasks/*/inference.ts", - "inference-tgi-import": "tsx scripts/inference-tgi-import.ts && prettier --write src/tasks/text-generation/spec/*.json && prettier --write src/tasks/chat-completion/spec/*.json", - "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write src/tasks/feature-extraction/spec/*.json" + "test": "vitest run" }, "type": "module", "files": [ @@ -48,9 +48,13 @@ ], "author": "Hugging Face", "license": "MIT", - "devDependencies": { - "@types/node": "^20.11.5", - "quicktype-core": "https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz", - "type-fest": "^3.13.1" - } + "tshy": { + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "main": "./dist/commonjs/index.js", + "types": "./dist/commonjs/index.d.ts", + "module": "./dist/esm/index.js" } diff --git a/packages/tasks/pnpm-lock.yaml b/packages/tasks/pnpm-lock.yaml index 741ee9a42..2b9f1883a 100644 --- a/packages/tasks/pnpm-lock.yaml +++ b/packages/tasks/pnpm-lock.yaml @@ -3,220 +3,3 @@ lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false - -devDependencies: - '@types/node': - specifier: ^20.11.5 - version: 20.11.5 - quicktype-core: - specifier: https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz - version: '@github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz' - type-fest: - specifier: ^3.13.1 - version: 3.13.1 - -packages: - - /@glideapps/ts-necessities@2.1.3: - resolution: {integrity: sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==} - dev: true - - /@types/node@20.11.5: - resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@types/urijs@1.19.25: - resolution: {integrity: sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==} - dev: true - - /abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - dependencies: - event-target-shim: 5.0.1 - dev: true - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true - - /browser-or-node@2.1.1: - resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==} - dev: true - - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - - /collection-utils@1.0.1: - resolution: {integrity: sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==} - dev: true - - /cross-fetch@4.0.0: - resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - dev: true - - /event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - dev: true - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true - - /is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - dev: true - - /js-base64@3.7.6: - resolution: {integrity: sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA==} - dev: true - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true - - /node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - - /pako@0.2.9: - resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} - dev: true - - /pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - dev: true - - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true - - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - dev: true - - /readable-stream@4.4.2: - resolution: {integrity: sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - dev: true - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /tiny-inflate@1.0.3: - resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} - dev: true - - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true - - /type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - dev: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /unicode-properties@1.4.1: - resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} - dependencies: - base64-js: 1.5.1 - unicode-trie: 2.0.0 - dev: true - - /unicode-trie@2.0.0: - resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} - dependencies: - pako: 0.2.9 - tiny-inflate: 1.0.3 - dev: true - - /urijs@1.19.11: - resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} - dev: true - - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: true - - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true - - /yaml@2.3.4: - resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} - engines: {node: '>= 14'} - dev: true - - '@github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz': - resolution: {tarball: https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz} - name: quicktype-core - version: 18.0.17 - dependencies: - '@glideapps/ts-necessities': 2.1.3 - '@types/urijs': 1.19.25 - browser-or-node: 2.1.1 - collection-utils: 1.0.1 - cross-fetch: 4.0.0 - is-url: 1.2.4 - js-base64: 3.7.6 - lodash: 4.17.21 - pako: 1.0.11 - pluralize: 8.0.0 - readable-stream: 4.4.2 - unicode-properties: 1.4.1 - urijs: 1.19.11 - wordwrap: 1.0.0 - yaml: 2.3.4 - transitivePeerDependencies: - - encoding - dev: true diff --git a/packages/tasks/scripts/generate-cts.ts b/packages/tasks/scripts/generate-cts.ts deleted file mode 100644 index 4c128a984..000000000 --- a/packages/tasks/scripts/generate-cts.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Just copy over the already generated .d.ts and .d.ts.map files to .d.cts and .d.cts.map files -import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; - -function recursiveCopy(path: string) { - for (const item of readdirSync(path)) { - if (item.endsWith(".d.ts")) { - const content = readFileSync(join(path, item), "utf-8"); - writeFileSync(join(path, item.replace(".d.ts", ".d.cts")), content.replaceAll(".d.ts.map", ".d.cts.map")); - } else if (item.endsWith(".d.ts.map")) { - const content = readFileSync(join(path, item), "utf-8"); - writeFileSync(join(path, item.replace(".d.ts.map", ".d.cts.map")), content.replaceAll(".d.ts", ".d.cts")); - } else if (statSync(join(path, item)).isDirectory()) { - recursiveCopy(join(path, item)); - } - } -} - -recursiveCopy("dist"); diff --git a/packages/tasks/tsconfig.local.json b/packages/tasks/tsconfig.local.json deleted file mode 100644 index aefb17827..000000000 --- a/packages/tasks/tsconfig.local.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src", "scripts"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 183074604..53ea212e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ devDependencies: semver: specifier: ^7.5.0 version: 7.5.0 + tshy: + specifier: ^3.0.2 + version: 3.0.2 tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.31)(typescript@5.4.2) @@ -954,6 +957,18 @@ packages: resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} dev: true + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1513,6 +1528,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1532,6 +1552,11 @@ packages: engines: {node: '>=10'} dev: true + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: true @@ -1785,6 +1810,11 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} dependencies: @@ -1806,6 +1836,21 @@ packages: fsevents: 2.3.3 dev: true + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: true @@ -2133,6 +2178,10 @@ packages: esutils: 2.0.3 dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /edge-paths@3.0.5: resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} engines: {node: '>=14.0.0'} @@ -2141,6 +2190,14 @@ packages: which: 2.0.2 dev: true + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: @@ -2684,6 +2741,14 @@ packages: is-callable: 1.2.7 dev: true + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /form-data-encoder@2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} @@ -2791,6 +2856,19 @@ packages: is-glob: 4.0.3 dev: true + /glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + foreground-child: 3.3.0 + jackspeak: 4.0.2 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + dev: true + /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} dependencies: @@ -3134,6 +3212,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3276,6 +3359,13 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /jackspeak@4.0.2: + resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + dev: true + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -3458,6 +3548,11 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /lru-cache@11.0.2: + resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} + engines: {node: 20 || >=22} + dev: true + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -3522,6 +3617,13 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -3554,6 +3656,11 @@ packages: engines: {node: '>=8'} dev: true + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /mitt@3.0.0: resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} dev: true @@ -3562,6 +3669,12 @@ packages: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: true + /mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + dev: true + /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} dependencies: @@ -3794,6 +3907,10 @@ packages: p-limit: 4.0.0 dev: true + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: true + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3856,6 +3973,14 @@ packages: minipass: 4.2.5 dev: true + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.0.2 + minipass: 7.1.2 + dev: true + /path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -3921,6 +4046,11 @@ packages: pathe: 1.1.1 dev: true + /polite-json@5.0.0: + resolution: {integrity: sha512-OLS/0XeUAcE8a2fdwemNja+udKgXNnY6yKVIXqAD2zVRx1KvY6Ato/rZ2vdzbxqYwPW0u6SCNC/bAMPNzpzxbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -4158,6 +4288,14 @@ packages: engines: {node: '>=8'} dev: true + /resolve-import@2.0.0: + resolution: {integrity: sha512-jpKjLibLuc8D1XEV2+7zb0aqN7I8d12u89g/v6IsgCzdVlccMQJq4TKkPw5fbhHdxhm7nbVtN+KvOTnjFf+nEA==} + engines: {node: 20 || >=22} + dependencies: + glob: 11.0.0 + walk-up-path: 4.0.0 + dev: true + /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true @@ -4208,6 +4346,15 @@ packages: glob: 9.3.1 dev: true + /rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + glob: 11.0.0 + package-json-from-dist: 1.0.1 + dev: true + /rollup@3.18.0: resolution: {integrity: sha512-J8C6VfEBjkvYPESMQYxKHxNOh4A5a3FlP+0BETGo34HEcE4eTlgCrO2+eWzlu2a/sHs2QUkZco+wscH7jhhgWg==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -4363,6 +4510,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /sirv@2.0.3: resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} engines: {node: '>= 10'} @@ -4426,6 +4578,24 @@ packages: internal-slot: 1.0.5 dev: true + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string.prototype.padend@3.1.6: resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} engines: {node: '>= 0.4'} @@ -4482,6 +4652,13 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.1.0 + dev: true + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -4570,6 +4747,18 @@ packages: periscopic: 3.1.0 dev: true + /sync-content@2.0.1: + resolution: {integrity: sha512-NI1mo514yFhr8pV/5Etvgh+pSBUIpoAKoiBIUwALVlQQNAwb40bTw8hhPFaip/dvv0GhpHVOq0vq8iY02ppLTg==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + glob: 11.0.0 + mkdirp: 3.0.1 + path-scurry: 2.0.0 + rimraf: 6.0.1 + tshy: 3.0.2 + dev: true + /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} dependencies: @@ -4665,6 +4854,24 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true + /tshy@3.0.2: + resolution: {integrity: sha512-8GkWnAfmNXxl8iDTZ1o2H4jdaj9H7HeDKkr5qd0ZhQBCNA41D3xqTyg2Ycs51VCfmjJ5e+0v9AUmD6ylAI9Bgw==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + chalk: 5.3.0 + chokidar: 3.6.0 + foreground-child: 3.3.0 + minimatch: 10.0.1 + mkdirp: 3.0.1 + polite-json: 5.0.0 + resolve-import: 2.0.0 + rimraf: 6.0.1 + sync-content: 2.0.1 + typescript: 5.6.3 + walk-up-path: 4.0.0 + dev: true + /tsup@6.7.0(postcss@8.4.31)(typescript@5.4.2): resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==} engines: {node: '>=14.18'} @@ -4785,6 +4992,12 @@ packages: hasBin: true dev: true + /typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + /ua-parser-js@1.0.34: resolution: {integrity: sha512-K9mwJm/DaB6mRLZfw6q8IMXipcrmuT6yfhYmwhAkuh+81sChuYstYA+znlgaflUPaYUa3odxKPKGw6Vw/lANew==} dev: true @@ -4960,6 +5173,11 @@ packages: - terser dev: true + /walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + dev: true + /webdriver@8.6.6: resolution: {integrity: sha512-cly5yf5BnHOrpF+wkT7ztlt++wjws63sIyfPGPVt9MQD+yutt3zW1dB1bXgAGVVvVQUAeIkjcrIc1t8+1crFgQ==} engines: {node: ^16.13 || >=18} @@ -5114,6 +5332,24 @@ packages: stackback: 0.0.2 dev: true + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 159379aaa..bd21daac7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,6 +5,7 @@ packages: - "packages/agents" - "packages/languages" - "packages/tasks" + - "packages/tasks-gen" - "packages/gguf" - "packages/jinja" - "packages/space-header" From 3fb007e4a286bb2ad283c9b1e98f6f2fb5f6c91f Mon Sep 17 00:00:00 2001 From: Mishig Date: Fri, 15 Nov 2024 06:58:36 -0400 Subject: [PATCH 38/97] [Conversational Snippet] add missing semicolons (#1032) [Conversational Snippet] add missing semicolons --- packages/tasks/src/snippets/js.spec.ts | 16 ++++++++-------- packages/tasks/src/snippets/js.ts | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/tasks/src/snippets/js.spec.ts b/packages/tasks/src/snippets/js.spec.ts index 644f9a548..50be868aa 100644 --- a/packages/tasks/src/snippets/js.spec.ts +++ b/packages/tasks/src/snippets/js.spec.ts @@ -12,9 +12,9 @@ describe("inference API snippets", () => { }; const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; -const client = new HfInference("api_token") +const client = new HfInference("api_token"); let out = ""; @@ -47,9 +47,9 @@ for await (const chunk of stream) { }; const snippet = getJsInferenceSnippet(model, "api_token", { streaming: false }) as InferenceSnippet[]; - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; -const client = new HfInference("api_token") +const client = new HfInference("api_token"); const chatCompletion = await client.chatCompletion({ model: "meta-llama/Llama-3.1-8B-Instruct", @@ -74,9 +74,9 @@ console.log(chatCompletion.choices[0].message);`); }; const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; -const client = new HfInference("api_token") +const client = new HfInference("api_token"); let out = ""; @@ -120,9 +120,9 @@ for await (const chunk of stream) { }; const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference" + expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; -const client = new HfInference("api_token") +const client = new HfInference("api_token"); let out = ""; diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index 2728bbf98..e1124fa1e 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -58,9 +58,9 @@ export const snippetTextGeneration = ( return [ { client: "huggingface.js", - content: `import { HfInference } from "@huggingface/inference" + content: `import { HfInference } from "@huggingface/inference"; -const client = new HfInference("${accessToken || `{API_TOKEN}`}") +const client = new HfInference("${accessToken || `{API_TOKEN}`}"); let out = ""; @@ -80,12 +80,12 @@ for await (const chunk of stream) { }, { client: "openai", - content: `import { OpenAI } from "openai" + content: `import { OpenAI } from "openai"; const client = new OpenAI({ baseURL: "https://api-inference.huggingface.co/v1/", apiKey: "${accessToken || `{API_TOKEN}`}" -}) +}); let out = ""; @@ -109,9 +109,9 @@ for await (const chunk of stream) { return [ { client: "huggingface.js", - content: `import { HfInference } from "@huggingface/inference" + content: `import { HfInference } from "@huggingface/inference"; -const client = new HfInference("${accessToken || `{API_TOKEN}`}") +const client = new HfInference("${accessToken || `{API_TOKEN}`}"); const chatCompletion = await client.chatCompletion({ model: "${model.id}", @@ -123,12 +123,12 @@ console.log(chatCompletion.choices[0].message);`, }, { client: "openai", - content: `import { OpenAI } from "openai" + content: `import { OpenAI } from "openai"; const client = new OpenAI({ baseURL: "https://api-inference.huggingface.co/v1/", apiKey: "${accessToken || `{API_TOKEN}`}" -}) +}); const chatCompletion = await client.chat.completions.create({ model: "${model.id}", From 0db316c885883e33d797f2fe272acf3be3eb3500 Mon Sep 17 00:00:00 2001 From: machineuser Date: Fri, 15 Nov 2024 11:00:04 +0000 Subject: [PATCH 39/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 8f2114ab2..3ae5aed3a 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.1", + "version": "0.13.2", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 8fc1f6ec7461189191215505b3522be688a9ab2a Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:30:32 +0100 Subject: [PATCH 40/97] feat(hub): adding pathsInfo function (#1031) ## Description Following discussion https://github.com/huggingface/huggingface.js/pull/1024 and incompatibility of using the `HEAD` request to get the same etag as the python library is using for populating the cache directory. This PR add the `pathsInfo` function that return the paths information including the LFS oid (or etag) if the file is a LFS pointer. As suggested by @coyotte508 in https://github.com/huggingface/huggingface.js/pull/1024#pullrequestreview-2434410169 ## Related issues Fixes https://github.com/huggingface/huggingface.js/issues/1023 (provide an alternative method to `fileDownloadInfo`. ## Tests - [x] unit tests has been added --- packages/hub/src/lib/index.ts | 1 + packages/hub/src/lib/paths-info.spec.ts | 75 +++++++++++++++ packages/hub/src/lib/paths-info.ts | 120 ++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 packages/hub/src/lib/paths-info.spec.ts create mode 100644 packages/hub/src/lib/paths-info.ts diff --git a/packages/hub/src/lib/index.ts b/packages/hub/src/lib/index.ts index 603674ea0..b79385dc5 100644 --- a/packages/hub/src/lib/index.ts +++ b/packages/hub/src/lib/index.ts @@ -19,6 +19,7 @@ export * from "./model-info"; export * from "./oauth-handle-redirect"; export * from "./oauth-login-url"; export * from "./parse-safetensors-metadata"; +export * from "./paths-info"; export * from "./space-info"; export * from "./upload-file"; export * from "./upload-files"; diff --git a/packages/hub/src/lib/paths-info.spec.ts b/packages/hub/src/lib/paths-info.spec.ts new file mode 100644 index 000000000..994d623ae --- /dev/null +++ b/packages/hub/src/lib/paths-info.spec.ts @@ -0,0 +1,75 @@ +import { expect, it, describe } from "vitest"; +import type { CommitInfo, PathInfo, SecurityFileStatus } from "./paths-info"; +import { pathsInfo } from "./paths-info"; + +describe("pathsInfo", () => { + it("should fetch LFS path info", async () => { + const result: PathInfo[] = await pathsInfo({ + repo: { + name: "bert-base-uncased", + type: "model", + }, + paths: ["tf_model.h5"], + revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", + }); + + expect(result).toHaveLength(1); + + const modelPathInfo = result[0]; + expect(modelPathInfo.path).toBe('tf_model.h5'); + expect(modelPathInfo.type).toBe('file'); + // lfs pointer, therefore lfs should be defined + expect(modelPathInfo?.lfs).toBeDefined(); + expect(modelPathInfo?.lfs?.oid).toBe("a7a17d6d844b5de815ccab5f42cad6d24496db3850a2a43d8258221018ce87d2"); + expect(modelPathInfo?.lfs?.size).toBe(536063208); + expect(modelPathInfo?.lfs?.pointerSize).toBe(134); + + // should not include expand info + expect(modelPathInfo.lastCommit).toBeUndefined(); + expect(modelPathInfo.securityFileStatus).toBeUndefined(); + }); + + it("expand parmas should fetch lastCommit and securityFileStatus", async () => { + const result: (PathInfo & { + lastCommit: CommitInfo, + securityFileStatus: SecurityFileStatus, + })[] = await pathsInfo({ + repo: { + name: "bert-base-uncased", + type: "model", + }, + paths: ["tf_model.h5"], + revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", + expand: true, // include + }); + + expect(result).toHaveLength(1); + + const modelPathInfo = result[0]; + + // should include expand info + expect(modelPathInfo.lastCommit).toBeDefined(); + expect(modelPathInfo.securityFileStatus).toBeDefined(); + + expect(modelPathInfo.lastCommit.id).toBe("dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7"); + expect(modelPathInfo.lastCommit.title).toBe("Update tf_model.h5"); + expect(modelPathInfo.lastCommit.date.getTime()).toBe(1569268124000); // 2019-09-23T19:48:44.000Z + }); + + it("non-LFS pointer should have lfs undefined", async () => { + const result: (PathInfo)[] = await pathsInfo({ + repo: { + name: "bert-base-uncased", + type: "model", + }, + paths: ["config.json"], + revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", + }); + + expect(result).toHaveLength(1); + + const modelPathInfo = result[0]; + expect(modelPathInfo.path).toBe("config.json"); + expect(modelPathInfo.lfs).toBeUndefined(); + }); +}); diff --git a/packages/hub/src/lib/paths-info.ts b/packages/hub/src/lib/paths-info.ts new file mode 100644 index 000000000..4c9a1de20 --- /dev/null +++ b/packages/hub/src/lib/paths-info.ts @@ -0,0 +1,120 @@ +import type { CredentialsParams, RepoDesignation } from "../types/public"; +import { checkCredentials } from "../utils/checkCredentials"; +import { toRepoId } from "../utils/toRepoId"; +import { HUB_URL } from "../consts"; +import { createApiError } from "../error"; + +export interface LfsPathInfo { + "oid": string, + "size": number, + "pointerSize": number +} + +export interface CommitInfo { + "id": string, + "title": string, + "date": Date, +} + +export interface SecurityFileStatus { + "status": string, +} + +export interface PathInfo { + path: string, + type: string, + oid: string, + size: number, + /** + * Only defined when path is LFS pointer + */ + lfs?: LfsPathInfo, + lastCommit?: CommitInfo, + securityFileStatus?: SecurityFileStatus +} + +// Define the overloaded signatures +export function pathsInfo( + params: { + repo: RepoDesignation; + paths: string[]; + expand: true; // if expand true + revision?: string; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise<(PathInfo & {lastCommit: CommitInfo, securityFileStatus: SecurityFileStatus })[]>; +export function pathsInfo( + params: { + repo: RepoDesignation; + paths: string[]; + expand?: boolean; + revision?: string; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise<(PathInfo)[]>; + +export async function pathsInfo( + params: { + repo: RepoDesignation; + paths: string[]; + expand?: boolean; + revision?: string; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise { + const accessToken = checkCredentials(params); + const repoId = toRepoId(params.repo); + + const hubUrl = params.hubUrl ?? HUB_URL; + + const url = `${hubUrl}/api/${repoId.type}s/${repoId.name}/paths-info/${encodeURIComponent(params.revision ?? "main")}`; + + const resp = await (params.fetch ?? fetch)(url, { + method: "POST", + headers: { + ...(params.credentials && { + Authorization: `Bearer ${accessToken}`, + }), + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + paths: params.paths, + expand: params.expand, + }), + }); + + if (!resp.ok) { + throw await createApiError(resp); + } + + const json: unknown = await resp.json(); + if(!Array.isArray(json)) throw new Error('malformed response: expected array'); + + return json.map((item: PathInfo) => ({ + path: item.path, + lfs: item.lfs, + type: item.type, + oid: item.oid, + size: item.size, + // expand fields + securityFileStatus: item.securityFileStatus, + lastCommit: item.lastCommit ? { + date: new Date(item.lastCommit.date), + title: item.lastCommit.title, + id: item.lastCommit.id, + }: undefined, + })); +} From 58bbe807c53820dfbe351a260273a09b582d1d8f Mon Sep 17 00:00:00 2001 From: machineuser Date: Fri, 15 Nov 2024 11:31:24 +0000 Subject: [PATCH 41/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/hub=200.20.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- packages/hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d9e5f3dc..77a4649cb 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or ```html ``` diff --git a/packages/hub/package.json b/packages/hub/package.json index e72409216..7802e2389 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/hub", "packageManager": "pnpm@8.10.5", - "version": "0.19.0", + "version": "0.20.0", "description": "Utilities to interact with the Hugging Face hub", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From cd0e7c61920631db0ebb70304ffdc184c58064fb Mon Sep 17 00:00:00 2001 From: Steven Zheng <58599908+Deep-unlearning@users.noreply.github.com> Date: Fri, 15 Nov 2024 13:37:06 +0100 Subject: [PATCH 42/97] Update ASR task page (#1015) Co-authored-by: Steven Zheng Co-authored-by: vb --- .../tasks/automatic-speech-recognition/data.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/tasks/src/tasks/automatic-speech-recognition/data.ts b/packages/tasks/src/tasks/automatic-speech-recognition/data.ts index 323c6fab3..b177a7f12 100644 --- a/packages/tasks/src/tasks/automatic-speech-recognition/data.ts +++ b/packages/tasks/src/tasks/automatic-speech-recognition/data.ts @@ -6,12 +6,16 @@ const taskData: TaskDataCustom = { description: "31,175 hours of multilingual audio-text dataset in 108 languages.", id: "mozilla-foundation/common_voice_17_0", }, + { + description: "Multilingual and diverse audio dataset with 101k hours of audio.", + id: "amphion/Emilia-Dataset", + }, { description: "A dataset with 44.6k hours of English speaker data and 6k hours of other language speakers.", id: "parler-tts/mls_eng", }, { - description: "A multi-lingual audio dataset with 370K hours of audio.", + description: "A multilingual audio dataset with 370K hours of audio.", id: "espnet/yodas", }, ], @@ -54,6 +58,10 @@ const taskData: TaskDataCustom = { description: "An end-to-end model that performs ASR and Speech Translation by MetaAI.", id: "facebook/seamless-m4t-v2-large", }, + { + description: "A powerful multilingual ASR and Speech Translation model by Nvidia.", + id: "nvidia/canary-1b", + }, { description: "Powerful speaker diarization model.", id: "pyannote/speaker-diarization-3.1", @@ -65,13 +73,17 @@ const taskData: TaskDataCustom = { id: "hf-audio/whisper-large-v3", }, { - description: "Fastest speech recognition application.", - id: "sanchit-gandhi/whisper-jax", + description: "Latest ASR model from Useful Sensors.", + id: "mrfakename/Moonshinex", }, { description: "A high quality speech and text translation model by Meta.", id: "facebook/seamless_m4t", }, + { + description: "A powerful multilingual ASR and Speech Translation model by Nvidia", + id: "nvidia/canary-1b", + }, ], summary: "Automatic Speech Recognition (ASR), also known as Speech to Text (STT), is the task of transcribing a given audio to text. It has many applications, such as voice user interfaces.", From 72b0d9bc51b8121b2129ac217072684613dabb4f Mon Sep 17 00:00:00 2001 From: Raj Aryan <73771884+rajaryan18@users.noreply.github.com> Date: Fri, 15 Nov 2024 19:13:34 +0530 Subject: [PATCH 43/97] :memo: Update Mask Generation Task (#432) Added about.md for Zero-shot-object-detection, text-to-3d and mask-generation. Also added use cases for them all. --------- Co-authored-by: Pedro Cuenca Co-authored-by: Eliott C. Co-authored-by: coyotte508 --- packages/tasks/.prettierignore | 3 ++- .../tasks/src/tasks/mask-generation/about.md | 10 ++++++++++ .../tasks/src/tasks/mask-generation/data.ts | 18 ++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/tasks/.prettierignore b/packages/tasks/.prettierignore index cac0c6949..09c2c8882 100644 --- a/packages/tasks/.prettierignore +++ b/packages/tasks/.prettierignore @@ -1,4 +1,5 @@ pnpm-lock.yaml # In order to avoid code samples to have tabs, they don't display well on npm README.md -dist \ No newline at end of file +dist +.tshy \ No newline at end of file diff --git a/packages/tasks/src/tasks/mask-generation/about.md b/packages/tasks/src/tasks/mask-generation/about.md index 18d6d38db..2fa3a65d2 100644 --- a/packages/tasks/src/tasks/mask-generation/about.md +++ b/packages/tasks/src/tasks/mask-generation/about.md @@ -12,6 +12,16 @@ Generating masks can facilitate learning, especially in semi or unsupervised lea For applications where humans are in the loop, masks highlight certain regions of images for humans to validate. +### Medical Imaging + +Mask generation models are used in medical imaging to aid in segmenting and analyzing specific regions. + +### Autonomous Vehicles + +Mask generation models are used to create segments and masks for obstacles and other objects in view. + +This page was made possible thanks to the efforts of [Raj Aryan](https://huggingface.co/thatrajaryan) and other contributors. + ## Task Variants ### Segmentation diff --git a/packages/tasks/src/tasks/mask-generation/data.ts b/packages/tasks/src/tasks/mask-generation/data.ts index 133e9a7f6..cc18380db 100644 --- a/packages/tasks/src/tasks/mask-generation/data.ts +++ b/packages/tasks/src/tasks/mask-generation/data.ts @@ -1,7 +1,16 @@ import type { TaskDataCustom } from "../index.js"; const taskData: TaskDataCustom = { - datasets: [], + datasets: [ + { + description: "Widely used benchmark dataset for multiple Vision tasks.", + id: "merve/coco2017", + }, + { + description: "Medical Imaging dataset of the Human Brain for segmentation and mask generating tasks", + id: "rocky93/BraTS_segmentation", + }, + ], demo: { inputs: [ { @@ -16,7 +25,12 @@ const taskData: TaskDataCustom = { }, ], }, - metrics: [], + metrics: [ + { + description: "IoU is used to measure the overlap between predicted mask and the ground truth mask.", + id: "Intersection over Union (IoU)", + }, + ], models: [ { description: "Small yet powerful mask generation model.", From afc250e2b7ebcdd72ef87a4f3962c4745c95c667 Mon Sep 17 00:00:00 2001 From: vb Date: Fri, 15 Nov 2024 20:38:52 +0100 Subject: [PATCH 44/97] feat: Add audio-text-to-text task. (#1033) There's an increasing number of Audio LMs: 1. https://huggingface.co/collections/reach-vb/ultravox-audio-language-model-release-67373b602af0a52b2a88ae71 2. https://huggingface.co/homebrewltd And.. many more. Will Open PRs after this is merged. --- packages/tasks/src/pipelines.ts | 6 ++++++ packages/tasks/src/tasks/index.ts | 2 ++ .../src/lib/components/PipelineIcon/PipelineIcon.svelte | 1 + 3 files changed, 9 insertions(+) diff --git a/packages/tasks/src/pipelines.ts b/packages/tasks/src/pipelines.ts index 237469b89..e272d2eef 100644 --- a/packages/tasks/src/pipelines.ts +++ b/packages/tasks/src/pipelines.ts @@ -355,6 +355,12 @@ export const PIPELINE_DATA = { modality: "audio", color: "green", }, + "audio-text-to-text": { + name: "Audio-Text-to-Text", + modality: "multimodal", + color: "red", + hideInDatasets: true, + }, "voice-activity-detection": { name: "Voice Activity Detection", modality: "audio", diff --git a/packages/tasks/src/tasks/index.ts b/packages/tasks/src/tasks/index.ts index 7392cfa91..1d4d3c811 100644 --- a/packages/tasks/src/tasks/index.ts +++ b/packages/tasks/src/tasks/index.ts @@ -116,6 +116,7 @@ export const TASKS_MODEL_LIBRARIES: Record = { "audio-classification": ["speechbrain", "transformers", "transformers.js"], "audio-to-audio": ["asteroid", "fairseq", "speechbrain"], "automatic-speech-recognition": ["espnet", "nemo", "speechbrain", "transformers", "transformers.js"], + "audio-text-to-text": [], "depth-estimation": ["transformers", "transformers.js"], "document-question-answering": ["transformers", "transformers.js"], "feature-extraction": ["sentence-transformers", "transformers", "transformers.js"], @@ -197,6 +198,7 @@ export const TASKS_DATA: Record = { "any-to-any": getData("any-to-any", placeholder), "audio-classification": getData("audio-classification", audioClassification), "audio-to-audio": getData("audio-to-audio", audioToAudio), + "audio-text-to-text": getData("audio-text-to-text", placeholder), "automatic-speech-recognition": getData("automatic-speech-recognition", automaticSpeechRecognition), "depth-estimation": getData("depth-estimation", depthEstimation), "document-question-answering": getData("document-question-answering", documentQuestionAnswering), diff --git a/packages/widgets/src/lib/components/PipelineIcon/PipelineIcon.svelte b/packages/widgets/src/lib/components/PipelineIcon/PipelineIcon.svelte index 1429e1cb4..0d85bf76a 100644 --- a/packages/widgets/src/lib/components/PipelineIcon/PipelineIcon.svelte +++ b/packages/widgets/src/lib/components/PipelineIcon/PipelineIcon.svelte @@ -73,6 +73,7 @@ "automatic-speech-recognition": IconAutomaticSpeechRecognition, "audio-to-audio": IconAudioToAudio, "audio-classification": IconAudioClassification, + "audio-text-to-text": IconAudioToAudio, "voice-activity-detection": IconVoiceActivityDetection, "depth-estimation": IconDepthEstimation, "image-classification": IconImageClassification, From b340e69604c3de29d53712b79f65ab9298194225 Mon Sep 17 00:00:00 2001 From: Mishig Date: Mon, 18 Nov 2024 11:02:12 +0100 Subject: [PATCH 45/97] export type InferenceSnippet from @hfjs/tasks (#1036) export type InferenceSnippet from @hfjs/tasks --- packages/tasks/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/tasks/src/index.ts b/packages/tasks/src/index.ts index a3f69c2b3..f11661a13 100644 --- a/packages/tasks/src/index.ts +++ b/packages/tasks/src/index.ts @@ -49,6 +49,8 @@ import * as snippets from "./snippets/index.js"; export * from "./gguf.js"; export { snippets }; +export type { InferenceSnippet } from "./snippets/index.js"; + export { SKUS, DEFAULT_MEMORY_OPTIONS } from "./hardware.js"; export type { HardwareSpec, SkuType } from "./hardware.js"; From f05749227ff1a9f0e1b0534db6f2d61bf0f5a739 Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 18 Nov 2024 10:03:00 +0000 Subject: [PATCH 46/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 3ae5aed3a..e9e64c0bf 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.2", + "version": "0.13.3", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 2e0c2c67ad68c90edcda6604f62b59e08192c047 Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:57:15 +0100 Subject: [PATCH 47/97] feat(hub): adding `downloadFileToCacheDir` (#1034) ## Description Following https://github.com/huggingface/huggingface.js/pull/1031 which added a `pathsInfo` method which can return the etag/commitHash for a given file. Allowing to be compliant with the `_hf_hub_download_to_cache_dir`[^1] method from the python library. [^1]: [huggingface_hub/file_download.py#L882](https://github.com/huggingface/huggingface_hub/blob/c547c839dbbe0163e3ca422d017daad7c7f9361f/src/huggingface_hub/file_download.py#L882) ## Potential issue The JS implementation do not handle the .lock files as the python library does.. This could be a problem if using the JS and PY function.. ? The JS could make a basic implementation of the lock file that the PY lib is doing if this is a hard requirement. ## Testing I wrote tests for the existing `downloadFile` function (no change to the implementation) and the new one added `downloadFileToCacheDir`. - [x] unit tests has been added --------- Co-authored-by: Eliott C. Co-authored-by: Eliott C. --- packages/hub/package.json | 1 + packages/hub/src/lib/cache-management.ts | 15 +- .../lib/download-file-to-cache-dir.spec.ts | 234 ++++++++++++++++++ .../hub/src/lib/download-file-to-cache-dir.ts | 129 ++++++++++ packages/hub/src/lib/download-file.spec.ts | 65 +++++ packages/hub/src/lib/index.ts | 1 + packages/hub/vitest-browser.config.mts | 2 +- 7 files changed, 442 insertions(+), 5 deletions(-) create mode 100644 packages/hub/src/lib/download-file-to-cache-dir.spec.ts create mode 100644 packages/hub/src/lib/download-file-to-cache-dir.ts create mode 100644 packages/hub/src/lib/download-file.spec.ts diff --git a/packages/hub/package.json b/packages/hub/package.json index 7802e2389..14af8c6fd 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -21,6 +21,7 @@ "./src/utils/sha256-node.ts": false, "./src/utils/FileBlob.ts": false, "./src/lib/cache-management.ts": false, + "./src/lib/download-file-to-cache-dir.ts": false, "./dist/index.js": "./dist/browser/index.js", "./dist/index.mjs": "./dist/browser/index.mjs" }, diff --git a/packages/hub/src/lib/cache-management.ts b/packages/hub/src/lib/cache-management.ts index aecbf271e..98c3be5b4 100644 --- a/packages/hub/src/lib/cache-management.ts +++ b/packages/hub/src/lib/cache-management.ts @@ -16,12 +16,19 @@ function getHuggingFaceHubCache(): string { return process.env["HUGGINGFACE_HUB_CACHE"] ?? getDefaultCachePath(); } -function getHFHubCache(): string { +export function getHFHubCachePath(): string { return process.env["HF_HUB_CACHE"] ?? getHuggingFaceHubCache(); } const FILES_TO_IGNORE: string[] = [".DS_Store"]; +export const REPO_ID_SEPARATOR: string = "--"; + +export function getRepoFolderName({ name, type }: RepoId): string { + const parts = [`${type}s`, ...name.split("/")] + return parts.join(REPO_ID_SEPARATOR); +} + export interface CachedFileInfo { path: string; /** @@ -63,7 +70,7 @@ export interface HFCacheInfo { } export async function scanCacheDir(cacheDir: string | undefined = undefined): Promise { - if (!cacheDir) cacheDir = getHFHubCache(); + if (!cacheDir) cacheDir = getHFHubCachePath(); const s = await stat(cacheDir); if (!s.isDirectory()) { @@ -107,12 +114,12 @@ export async function scanCacheDir(cacheDir: string | undefined = undefined): Pr export async function scanCachedRepo(repoPath: string): Promise { // get the directory name const name = basename(repoPath); - if (!name.includes("--")) { + if (!name.includes(REPO_ID_SEPARATOR)) { throw new Error(`Repo path is not a valid HuggingFace cache directory: ${name}`); } // parse the repoId from directory name - const [type, ...remaining] = name.split("--"); + const [type, ...remaining] = name.split(REPO_ID_SEPARATOR); const repoType = parseRepoType(type); const repoId = remaining.join("/"); diff --git a/packages/hub/src/lib/download-file-to-cache-dir.spec.ts b/packages/hub/src/lib/download-file-to-cache-dir.spec.ts new file mode 100644 index 000000000..05e2e6de9 --- /dev/null +++ b/packages/hub/src/lib/download-file-to-cache-dir.spec.ts @@ -0,0 +1,234 @@ +import { expect, test, describe, vi, beforeEach } from "vitest"; +import type { RepoDesignation, RepoId } from "../types/public"; +import { dirname, join } from "node:path"; +import { lstat, mkdir, stat, symlink, writeFile, rename } from "node:fs/promises"; +import { pathsInfo } from "./paths-info"; +import type { Stats } from "node:fs"; +import { getHFHubCachePath, getRepoFolderName } from "./cache-management"; +import { toRepoId } from "../utils/toRepoId"; +import { downloadFileToCacheDir } from "./download-file-to-cache-dir"; + +vi.mock('node:fs/promises', () => ({ + writeFile: vi.fn(), + rename: vi.fn(), + symlink: vi.fn(), + lstat: vi.fn(), + mkdir: vi.fn(), + stat: vi.fn() +})); + +vi.mock('./paths-info', () => ({ + pathsInfo: vi.fn(), +})); + +const DUMMY_REPO: RepoId = { + name: 'hello-world', + type: 'model', +}; + +const DUMMY_ETAG = "dummy-etag"; + +// utility test method to get blob file path +function _getBlobFile(params: { + repo: RepoDesignation; + etag: string; + cacheDir?: string, // default to {@link getHFHubCache} +}) { + return join(params.cacheDir ?? getHFHubCachePath(), getRepoFolderName(toRepoId(params.repo)), "blobs", params.etag); +} + +// utility test method to get snapshot file path +function _getSnapshotFile(params: { + repo: RepoDesignation; + path: string; + revision : string; + cacheDir?: string, // default to {@link getHFHubCache} +}) { + return join(params.cacheDir ?? getHFHubCachePath(), getRepoFolderName(toRepoId(params.repo)), "snapshots", params.revision, params.path); +} + +describe('downloadFileToCacheDir', () => { + const fetchMock: typeof fetch = vi.fn(); + beforeEach(() => { + vi.resetAllMocks(); + // mock 200 request + vi.mocked(fetchMock).mockResolvedValue({ + status: 200, + ok: true, + body: 'dummy-body' + } as unknown as Response); + + // prevent to use caching + vi.mocked(stat).mockRejectedValue(new Error('Do not exists')); + vi.mocked(lstat).mockRejectedValue(new Error('Do not exists')); + }); + + test('should throw an error if fileDownloadInfo return nothing', async () => { + await expect(async () => { + await downloadFileToCacheDir({ + repo: DUMMY_REPO, + path: '/README.md', + fetch: fetchMock, + }); + }).rejects.toThrowError('cannot get path info for /README.md'); + + expect(pathsInfo).toHaveBeenCalledWith(expect.objectContaining({ + repo: DUMMY_REPO, + paths: ['/README.md'], + fetch: fetchMock, + })); + }); + + test('existing symlinked and blob should not re-download it', async () => { + // ///snapshots/README.md + const expectPointer = _getSnapshotFile({ + repo: DUMMY_REPO, + path: '/README.md', + revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", + }); + // stat ensure a symlink and the pointed file exists + vi.mocked(stat).mockResolvedValue({} as Stats) // prevent default mocked reject + + const output = await downloadFileToCacheDir({ + repo: DUMMY_REPO, + path: '/README.md', + fetch: fetchMock, + revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", + }); + + expect(stat).toHaveBeenCalledOnce(); + // Get call argument for stat + const starArg = vi.mocked(stat).mock.calls[0][0]; + + expect(starArg).toBe(expectPointer) + expect(fetchMock).not.toHaveBeenCalledWith(); + + expect(output).toBe(expectPointer); + }); + + test('existing blob should only create the symlink', async () => { + // ///snapshots/README.md + const expectPointer = _getSnapshotFile({ + repo: DUMMY_REPO, + path: '/README.md', + revision: "dummy-commit-hash", + }); + // //blobs/ + const expectedBlob = _getBlobFile({ + repo: DUMMY_REPO, + etag: DUMMY_ETAG, + }); + + // mock existing blob only no symlink + vi.mocked(lstat).mockResolvedValue({} as Stats); + // mock pathsInfo resolve content + vi.mocked(pathsInfo).mockResolvedValue([{ + oid: DUMMY_ETAG, + size: 55, + path: 'README.md', + type: 'file', + lastCommit: { + date: new Date(), + id: 'dummy-commit-hash', + title: 'Commit msg', + }, + }]); + + const output = await downloadFileToCacheDir({ + repo: DUMMY_REPO, + path: '/README.md', + fetch: fetchMock, + }); + + expect(stat).not.toHaveBeenCalled(); + // should have check for the blob + expect(lstat).toHaveBeenCalled(); + expect(vi.mocked(lstat).mock.calls[0][0]).toBe(expectedBlob); + + // symlink should have been created + expect(symlink).toHaveBeenCalledOnce(); + // no download done + expect(fetchMock).not.toHaveBeenCalled(); + + expect(output).toBe(expectPointer); + }); + + test('expect resolve value to be the pointer path of downloaded file', async () => { + // ///snapshots/README.md + const expectPointer = _getSnapshotFile({ + repo: DUMMY_REPO, + path: '/README.md', + revision: "dummy-commit-hash", + }); + // //blobs/ + const expectedBlob = _getBlobFile({ + repo: DUMMY_REPO, + etag: DUMMY_ETAG, + }); + + vi.mocked(pathsInfo).mockResolvedValue([{ + oid: DUMMY_ETAG, + size: 55, + path: 'README.md', + type: 'file', + lastCommit: { + date: new Date(), + id: 'dummy-commit-hash', + title: 'Commit msg', + }, + }]); + + const output = await downloadFileToCacheDir({ + repo: DUMMY_REPO, + path: '/README.md', + fetch: fetchMock, + }); + + // expect blobs and snapshots folder to have been mkdir + expect(vi.mocked(mkdir).mock.calls[0][0]).toBe(dirname(expectedBlob)); + expect(vi.mocked(mkdir).mock.calls[1][0]).toBe(dirname(expectPointer)); + + expect(output).toBe(expectPointer); + }); + + test('should write fetch response to blob', async () => { + // ///snapshots/README.md + const expectPointer = _getSnapshotFile({ + repo: DUMMY_REPO, + path: '/README.md', + revision: "dummy-commit-hash", + }); + // //blobs/ + const expectedBlob = _getBlobFile({ + repo: DUMMY_REPO, + etag: DUMMY_ETAG, + }); + + // mock pathsInfo resolve content + vi.mocked(pathsInfo).mockResolvedValue([{ + oid: DUMMY_ETAG, + size: 55, + path: 'README.md', + type: 'file', + lastCommit: { + date: new Date(), + id: 'dummy-commit-hash', + title: 'Commit msg', + }, + }]); + + await downloadFileToCacheDir({ + repo: DUMMY_REPO, + path: '/README.md', + fetch: fetchMock, + }); + + const incomplete = `${expectedBlob}.incomplete`; + // 1. should write fetch#response#body to incomplete file + expect(writeFile).toHaveBeenCalledWith(incomplete, 'dummy-body'); + // 2. should rename the incomplete to the blob expected name + expect(rename).toHaveBeenCalledWith(incomplete, expectedBlob); + // 3. should create symlink pointing to blob + expect(symlink).toHaveBeenCalledWith(expectedBlob, expectPointer); + }); +}); \ No newline at end of file diff --git a/packages/hub/src/lib/download-file-to-cache-dir.ts b/packages/hub/src/lib/download-file-to-cache-dir.ts new file mode 100644 index 000000000..72869f307 --- /dev/null +++ b/packages/hub/src/lib/download-file-to-cache-dir.ts @@ -0,0 +1,129 @@ +import { getHFHubCachePath, getRepoFolderName } from "./cache-management"; +import { dirname, join } from "node:path"; +import { writeFile, rename, symlink, lstat, mkdir, stat } from "node:fs/promises"; +import type { CommitInfo, PathInfo } from "./paths-info"; +import { pathsInfo } from "./paths-info"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; +import { toRepoId } from "../utils/toRepoId"; +import { downloadFile } from "./download-file"; + +export const REGEX_COMMIT_HASH: RegExp = new RegExp("^[0-9a-f]{40}$"); + +function getFilePointer(storageFolder: string, revision: string, relativeFilename: string): string { + const snapshotPath = join(storageFolder, "snapshots"); + return join(snapshotPath, revision, relativeFilename); +} + +/** + * handy method to check if a file exists, or the pointer of a symlinks exists + * @param path + * @param followSymlinks + */ +async function exists(path: string, followSymlinks?: boolean): Promise { + try { + if(followSymlinks) { + await stat(path); + } else { + await lstat(path); + } + return true; + } catch (err: unknown) { + return false; + } +} + +/** + * Download a given file if it's not already present in the local cache. + * @param params + * @return the symlink to the blob object + */ +export async function downloadFileToCacheDir( + params: { + repo: RepoDesignation; + path: string; + /** + * If true, will download the raw git file. + * + * For example, when calling on a file stored with Git LFS, the pointer file will be downloaded instead. + */ + raw?: boolean; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + * + * @default "main" + */ + revision?: string; + hubUrl?: string; + cacheDir?: string, + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise { + // get revision provided or default to main + const revision = params.revision ?? "main"; + const cacheDir = params.cacheDir ?? getHFHubCachePath(); + // get repo id + const repoId = toRepoId(params.repo); + // get storage folder + const storageFolder = join(cacheDir, getRepoFolderName(repoId)); + + let commitHash: string | undefined; + + // if user provides a commitHash as revision, and they already have the file on disk, shortcut everything. + if (REGEX_COMMIT_HASH.test(revision)) { + commitHash = revision; + const pointerPath = getFilePointer(storageFolder, revision, params.path); + if (await exists(pointerPath, true)) return pointerPath; + } + + const pathsInformation: (PathInfo & { lastCommit: CommitInfo })[] = await pathsInfo({ + ...params, + paths: [params.path], + revision: revision, + expand: true, + }); + if (!pathsInformation || pathsInformation.length !== 1) throw new Error(`cannot get path info for ${params.path}`); + + let etag: string; + if (pathsInformation[0].lfs) { + etag = pathsInformation[0].lfs.oid; // get the LFS pointed file oid + } else { + etag = pathsInformation[0].oid; // get the repo file if not a LFS pointer + } + + const pointerPath = getFilePointer(storageFolder, commitHash ?? pathsInformation[0].lastCommit.id, params.path); + const blobPath = join(storageFolder, "blobs", etag); + + // mkdir blob and pointer path parent directory + await mkdir(dirname(blobPath), { recursive: true }); + await mkdir(dirname(pointerPath), { recursive: true }); + + // We might already have the blob but not the pointer + // shortcut the download if needed + if (await exists(blobPath)) { + // create symlinks in snapshot folder to blob object + await symlink(blobPath, pointerPath); + return pointerPath; + } + + const incomplete = `${blobPath}.incomplete`; + console.debug(`Downloading ${params.path} to ${incomplete}`); + + const response: Response | null = await downloadFile({ + ...params, + revision: commitHash, + }); + + if (!response || !response.ok || !response.body) throw new Error(`invalid response for file ${params.path}`); + + // @ts-expect-error resp.body is a Stream, but Stream in internal to node + await writeFile(incomplete, response.body); + + // rename .incomplete file to expect blob + await rename(incomplete, blobPath); + // create symlinks in snapshot folder to blob object + await symlink(blobPath, pointerPath); + return pointerPath; +} diff --git a/packages/hub/src/lib/download-file.spec.ts b/packages/hub/src/lib/download-file.spec.ts new file mode 100644 index 000000000..f442f152a --- /dev/null +++ b/packages/hub/src/lib/download-file.spec.ts @@ -0,0 +1,65 @@ +import { expect, test, describe, vi } from "vitest"; +import { downloadFile } from "./download-file"; +import type { RepoId } from "../types/public"; + +const DUMMY_REPO: RepoId = { + name: 'hello-world', + type: 'model', +}; + +describe("downloadFile", () => { + test("hubUrl params should overwrite HUB_URL", async () => { + const fetchMock: typeof fetch = vi.fn(); + vi.mocked(fetchMock).mockResolvedValue({ + status: 200, + ok: true, + } as Response); + + await downloadFile({ + repo: DUMMY_REPO, + path: '/README.md', + hubUrl: 'http://dummy-hub', + fetch: fetchMock, + }); + + expect(fetchMock).toHaveBeenCalledWith('http://dummy-hub/hello-world/resolve/main//README.md', expect.anything()); + }); + + test("raw params should use raw url", async () => { + const fetchMock: typeof fetch = vi.fn(); + vi.mocked(fetchMock).mockResolvedValue({ + status: 200, + ok: true, + } as Response); + + await downloadFile({ + repo: DUMMY_REPO, + path: 'README.md', + raw: true, + fetch: fetchMock, + }); + + expect(fetchMock).toHaveBeenCalledWith('https://huggingface.co/hello-world/raw/main/README.md', expect.anything()); + }); + + test("internal server error should propagate the error", async () => { + const fetchMock: typeof fetch = vi.fn(); + vi.mocked(fetchMock).mockResolvedValue({ + status: 500, + ok: false, + headers: new Map([["Content-Type", "application/json"]]), + json: () => ({ + error: 'Dummy internal error', + }), + } as unknown as Response); + + await expect(async () => { + await downloadFile({ + repo: DUMMY_REPO, + path: 'README.md', + raw: true, + fetch: fetchMock, + }); + }).rejects.toThrowError('Dummy internal error'); + }); +}); \ No newline at end of file diff --git a/packages/hub/src/lib/index.ts b/packages/hub/src/lib/index.ts index b79385dc5..c2a2fbe06 100644 --- a/packages/hub/src/lib/index.ts +++ b/packages/hub/src/lib/index.ts @@ -8,6 +8,7 @@ export * from "./delete-file"; export * from "./delete-files"; export * from "./delete-repo"; export * from "./download-file"; +export * from "./download-file-to-cache-dir"; export * from "./file-download-info"; export * from "./file-exists"; export * from "./list-commits"; diff --git a/packages/hub/vitest-browser.config.mts b/packages/hub/vitest-browser.config.mts index e106a2fba..60fcbfbfc 100644 --- a/packages/hub/vitest-browser.config.mts +++ b/packages/hub/vitest-browser.config.mts @@ -2,6 +2,6 @@ import { configDefaults, defineConfig } from "vitest/config"; export default defineConfig({ test: { - exclude: [...configDefaults.exclude, "src/utils/FileBlob.spec.ts", "src/lib/cache-management.spec.ts"], + exclude: [...configDefaults.exclude, "src/utils/FileBlob.spec.ts", "src/lib/cache-management.spec.ts", "src/lib/download-file-to-cache-dir.spec.ts"], }, }); From f1685ed2470938e10be65496b1856a5d8700a6c7 Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 18 Nov 2024 13:58:22 +0000 Subject: [PATCH 48/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/hub=200.21.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- packages/hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77a4649cb..4fb9b797f 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or ```html ``` diff --git a/packages/hub/package.json b/packages/hub/package.json index 14af8c6fd..04486821d 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/hub", "packageManager": "pnpm@8.10.5", - "version": "0.20.0", + "version": "0.21.0", "description": "Utilities to interact with the Hugging Face hub", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From b86390918dca41af3fe5ad323f4e283658161a8a Mon Sep 17 00:00:00 2001 From: Lucain Date: Mon, 18 Nov 2024 15:23:20 +0100 Subject: [PATCH 49/97] Fix zero-shot tasks specs (#1037) Related to [slack thread](https://huggingface.slack.com/archives/C069KSP486B/p1731923978189269) (private). This PR fixes the specs for `zero-shot-classification`, `zero-shot-image-classification` and `zero-shot-object-detection`. The candidate labels must be sent as parameters, not in `inputs`. The Inference API itself **did not change**, it's just the specs that were not aligned with the existing API. --- packages/tasks/src/tasks/index.ts | 1 - .../zero-shot-classification/inference.ts | 28 +++++----------- .../zero-shot-classification/spec/input.json | 33 ++++++++----------- .../inference.ts | 28 +++++----------- .../spec/input.json | 32 ++++++++---------- .../zero-shot-object-detection/inference.ts | 20 +++++------ .../spec/input.json | 31 ++++++++--------- 7 files changed, 65 insertions(+), 108 deletions(-) diff --git a/packages/tasks/src/tasks/index.ts b/packages/tasks/src/tasks/index.ts index 1d4d3c811..c1df8116d 100644 --- a/packages/tasks/src/tasks/index.ts +++ b/packages/tasks/src/tasks/index.ts @@ -102,7 +102,6 @@ export type * from "./zero-shot-image-classification/inference.js"; export type { BoundingBox, ZeroShotObjectDetectionInput, - ZeroShotObjectDetectionInputData, ZeroShotObjectDetectionOutput, ZeroShotObjectDetectionOutputElement, } from "./zero-shot-object-detection/inference.js"; diff --git a/packages/tasks/src/tasks/zero-shot-classification/inference.ts b/packages/tasks/src/tasks/zero-shot-classification/inference.ts index 20e0d369a..68717f406 100644 --- a/packages/tasks/src/tasks/zero-shot-classification/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-classification/inference.ts @@ -8,27 +8,13 @@ */ export interface ZeroShotClassificationInput { /** - * The input text data, with candidate labels + * The text to classify */ - inputs: ZeroShotClassificationInputData; + inputs: string; /** * Additional inference parameters */ - parameters?: ZeroShotClassificationParameters; - [property: string]: unknown; -} -/** - * The input text data, with candidate labels - */ -export interface ZeroShotClassificationInputData { - /** - * The set of possible class labels to classify the text into. - */ - candidateLabels: string[]; - /** - * The text to classify - */ - text: string; + parameters: ZeroShotClassificationParameters; [property: string]: unknown; } /** @@ -38,8 +24,12 @@ export interface ZeroShotClassificationInputData { */ export interface ZeroShotClassificationParameters { /** - * The sentence used in conjunction with candidateLabels to attempt the text classification - * by replacing the placeholder with the candidate labels. + * The set of possible class labels to classify the text into. + */ + candidate_labels: string[]; + /** + * The sentence used in conjunction with `candidate_labels` to attempt the text + * classification by replacing the placeholder with the candidate labels. */ hypothesis_template?: string; /** diff --git a/packages/tasks/src/tasks/zero-shot-classification/spec/input.json b/packages/tasks/src/tasks/zero-shot-classification/spec/input.json index c955f2769..fb875bac6 100644 --- a/packages/tasks/src/tasks/zero-shot-classification/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-classification/spec/input.json @@ -6,23 +6,8 @@ "type": "object", "properties": { "inputs": { - "description": "The input text data, with candidate labels", - "type": "object", - "title": "ZeroShotClassificationInputData", - "properties": { - "text": { - "type": "string", - "description": "The text to classify" - }, - "candidateLabels": { - "type": "array", - "description": "The set of possible class labels to classify the text into.", - "items": { - "type": "string" - } - } - }, - "required": ["text", "candidateLabels"] + "description": "The text to classify", + "type": "string" }, "parameters": { "description": "Additional inference parameters", @@ -35,16 +20,24 @@ "description": "Additional inference parameters for Zero Shot Classification", "type": "object", "properties": { + "candidate_labels": { + "type": "array", + "description": "The set of possible class labels to classify the text into.", + "items": { + "type": "string" + } + }, "hypothesis_template": { "type": "string", - "description": "The sentence used in conjunction with candidateLabels to attempt the text classification by replacing the placeholder with the candidate labels." + "description": "The sentence used in conjunction with `candidate_labels` to attempt the text classification by replacing the placeholder with the candidate labels." }, "multi_label": { "type": "boolean", "description": "Whether multiple candidate labels can be true. If false, the scores are normalized such that the sum of the label likelihoods for each sequence is 1. If true, the labels are considered independent and probabilities are normalized for each candidate." } - } + }, + "required": ["candidate_labels"] } }, - "required": ["inputs"] + "required": ["inputs", "parameters"] } diff --git a/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts b/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts index 44ce76173..c1cd4d7a2 100644 --- a/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts @@ -8,27 +8,13 @@ */ export interface ZeroShotImageClassificationInput { /** - * The input image data, with candidate labels + * The input image data to classify as a base64-encoded string. */ - inputs: ZeroShotImageClassificationInputData; + inputs: string; /** * Additional inference parameters */ - parameters?: ZeroShotImageClassificationParameters; - [property: string]: unknown; -} -/** - * The input image data, with candidate labels - */ -export interface ZeroShotImageClassificationInputData { - /** - * The candidate labels for this image - */ - candidateLabels: string[]; - /** - * The image data to classify - */ - image: unknown; + parameters: ZeroShotImageClassificationParameters; [property: string]: unknown; } /** @@ -38,8 +24,12 @@ export interface ZeroShotImageClassificationInputData { */ export interface ZeroShotImageClassificationParameters { /** - * The sentence used in conjunction with candidateLabels to attempt the text classification - * by replacing the placeholder with the candidate labels. + * The candidate labels for this image + */ + candidate_labels: string[]; + /** + * The sentence used in conjunction with `candidate_labels` to attempt the image + * classification by replacing the placeholder with the candidate labels. */ hypothesis_template?: string; [property: string]: unknown; diff --git a/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json b/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json index dfdababc7..85e88d4f2 100644 --- a/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json @@ -6,22 +6,8 @@ "type": "object", "properties": { "inputs": { - "description": "The input image data, with candidate labels", - "type": "object", - "title": "ZeroShotImageClassificationInputData", - "properties": { - "image": { - "description": "The image data to classify" - }, - "candidateLabels": { - "description": "The candidate labels for this image", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["image", "candidateLabels"] + "type": "string", + "description": "The input image data to classify as a base64-encoded string." }, "parameters": { "description": "Additional inference parameters", @@ -34,12 +20,20 @@ "description": "Additional inference parameters for Zero Shot Image Classification", "type": "object", "properties": { + "candidate_labels": { + "description": "The candidate labels for this image", + "type": "array", + "items": { + "type": "string" + } + }, "hypothesis_template": { "type": "string", - "description": "The sentence used in conjunction with candidateLabels to attempt the text classification by replacing the placeholder with the candidate labels." + "description": "The sentence used in conjunction with `candidate_labels` to attempt the image classification by replacing the placeholder with the candidate labels." } - } + }, + "required": ["candidate_labels"] } }, - "required": ["inputs"] + "required": ["inputs", "parameters"] } diff --git a/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts b/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts index 87447ca0a..dea72430c 100644 --- a/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts @@ -8,29 +8,25 @@ */ export interface ZeroShotObjectDetectionInput { /** - * The input image data, with candidate labels + * The input image data as a base64-encoded string. */ - inputs: ZeroShotObjectDetectionInputData; + inputs: string; /** * Additional inference parameters */ - parameters?: { - [key: string]: unknown; - }; + parameters: ZeroShotObjectDetectionParameters; [property: string]: unknown; } /** - * The input image data, with candidate labels + * Additional inference parameters + * + * Additional inference parameters for Zero Shot Object Detection */ -export interface ZeroShotObjectDetectionInputData { +export interface ZeroShotObjectDetectionParameters { /** * The candidate labels for this image */ - candidateLabels: string[]; - /** - * The image data to generate bounding boxes from - */ - image: unknown; + candidate_labels: string[]; [property: string]: unknown; } /** diff --git a/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json b/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json index 7c9aa15ac..8b57cce72 100644 --- a/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json @@ -6,22 +6,8 @@ "type": "object", "properties": { "inputs": { - "description": "The input image data, with candidate labels", - "type": "object", - "title": "ZeroShotObjectDetectionInputData", - "properties": { - "image": { - "description": "The image data to generate bounding boxes from" - }, - "candidateLabels": { - "description": "The candidate labels for this image", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["image", "candidateLabels"] + "description": "The input image data as a base64-encoded string.", + "type": "string" }, "parameters": { "description": "Additional inference parameters", @@ -33,8 +19,17 @@ "title": "ZeroShotObjectDetectionParameters", "description": "Additional inference parameters for Zero Shot Object Detection", "type": "object", - "properties": {} + "properties": { + "candidate_labels": { + "description": "The candidate labels for this image", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["candidate_labels"] } }, - "required": ["inputs"] + "required": ["inputs", "parameters"] } From f51b2e30b646a384f778ca1644f7e8d18f091024 Mon Sep 17 00:00:00 2001 From: Lucain Date: Mon, 18 Nov 2024 16:40:34 +0100 Subject: [PATCH 50/97] Run tasks-gen scripts automatically (#964) This PR adds a Github Action to automatically run the `@huggingface/tasks-gen` scripts and open a PR if anything has changed. The workflow is triggered once a day (3am) and can be triggered manually if needed. Here is an example of auto-generated PR: https://github.com/huggingface/huggingface.js/pull/1030. --- Note: lint issues seems unrelated. But it doesn't seem to happen on main (see [here](https://github.com/huggingface/huggingface.js/actions/workflows/lint.yml?query=branch%3Amain)) so I don't know what's causing it :confused: --------- Co-authored-by: Pauline Bailly-Masson <155966238+paulinebm@users.noreply.github.com> --- .github/workflows/update-specs.yml | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/update-specs.yml diff --git a/.github/workflows/update-specs.yml b/.github/workflows/update-specs.yml new file mode 100644 index 000000000..d5d31decb --- /dev/null +++ b/.github/workflows/update-specs.yml @@ -0,0 +1,63 @@ +name: Tasks - Update specs + +on: + workflow_dispatch: + schedule: + - cron: "0 3 * * *" # Every day at 3am + +concurrency: + group: update-specs + cancel-in-progress: true + +defaults: + run: + working-directory: packages/tasks-gen + +jobs: + pull_request: + runs-on: ubuntu-latest + steps: + # Setup + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: "20" + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + run_install: true + + # Generate specs + - run: pnpm run inference-tgi-import + - run: pnpm run inference-tei-import + - run: pnpm run inference-codegen + + # Check changes + - run: git status + + # Create or update Pull Request + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.TOKEN_INFERENCE_SYNC_BOT }} + commit-message: Update tasks specs (automated commit) + branch: update-tasks-specs-automated-pr + delete-branch: true + title: "[Bot] Update tasks specs" + body: | + This PR updates the @huggingface/tasks specs. It has been generated by running: + ```sh + pnpm run inference-tgi-import + pnpm run inference-tei-import + pnpm run inference-codegen + ``` + + This PR was automatically created by the [Tasks - Update specs workflow](https://github.com/huggingface/huggingface.js/blob/main/.github/update-specs.yml). + + Make sure the changes are correct before merging. + labels: | + tasks + specs + reviewers: | + Wauplin + hanouticelina From 9cb9acff8971e62df4502f6091830db7687299ca Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 18 Nov 2024 16:14:57 +0000 Subject: [PATCH 51/97] Remove "words" key from DQA output (#1040) cc @Wauplin - this matches `transformers` because `transformers` never outputs a `words` key. I'll make another PR to `transformers` to remove the key from the docstrings as well. --- .../src/tasks/document-question-answering/inference.ts | 4 ---- .../tasks/document-question-answering/spec/output.json | 9 +-------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/tasks/src/tasks/document-question-answering/inference.ts b/packages/tasks/src/tasks/document-question-answering/inference.ts index 1636dce9d..9c937b29a 100644 --- a/packages/tasks/src/tasks/document-question-answering/inference.ts +++ b/packages/tasks/src/tasks/document-question-answering/inference.ts @@ -102,9 +102,5 @@ export interface DocumentQuestionAnsweringOutputElement { * boxes). */ start: number; - /** - * The index of each word/box pair that is in the answer - */ - words: number[]; [property: string]: unknown; } diff --git a/packages/tasks/src/tasks/document-question-answering/spec/output.json b/packages/tasks/src/tasks/document-question-answering/spec/output.json index 4fda3771a..f8d0c20fe 100644 --- a/packages/tasks/src/tasks/document-question-answering/spec/output.json +++ b/packages/tasks/src/tasks/document-question-answering/spec/output.json @@ -22,15 +22,8 @@ "end": { "type": "integer", "description": "The end word index of the answer (in the OCR\u2019d version of the input or provided word boxes)." - }, - "words": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "The index of each word/box pair that is in the answer" } }, - "required": ["answer", "score", "start", "end", "words"] + "required": ["answer", "score", "start", "end"] } } From 352320eb329bc150fc471fbda42dbffc65f96e66 Mon Sep 17 00:00:00 2001 From: Steven Zheng <58599908+Deep-unlearning@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:37:06 +0100 Subject: [PATCH 52/97] Update TTS task page (#1014) Co-authored-by: Steven Zheng Co-authored-by: vb --- .../tasks/src/tasks/text-to-speech/data.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/tasks/src/tasks/text-to-speech/data.ts b/packages/tasks/src/tasks/text-to-speech/data.ts index afa7471cf..70ac91898 100644 --- a/packages/tasks/src/tasks/text-to-speech/data.ts +++ b/packages/tasks/src/tasks/text-to-speech/data.ts @@ -11,6 +11,10 @@ const taskData: TaskDataCustom = { description: "Multi-speaker English dataset.", id: "mythicinfinity/libritts_r", }, + { + description: "Mulit-lingual dataset.", + id: "facebook/multilingual_librispeech", + }, ], demo: { inputs: [ @@ -35,20 +39,24 @@ const taskData: TaskDataCustom = { ], models: [ { - description: "A powerful TTS model.", + description: "A prompt based, powerful TTS model.", id: "parler-tts/parler-tts-large-v1", }, + { + description: "A powerful TTS model that supports English and Chinese.", + id: "SWivid/F5-TTS", + }, { description: "A massively multi-lingual TTS model.", id: "coqui/XTTS-v2", }, { - description: "Robust TTS model.", - id: "metavoiceio/metavoice-1B-v0.1", + description: "A powerful TTS model.", + id: "amphion/MaskGCT", }, { - description: "A prompt based, powerful TTS model.", - id: "parler-tts/parler_tts_mini_v0.1", + description: "A Llama based TTS model.", + id: "OuteAI/OuteTTS-0.1-350M", }, ], spaces: [ @@ -66,8 +74,8 @@ const taskData: TaskDataCustom = { id: "mrfakename/E2-F5-TTS", }, { - description: "An application that synthesizes speech for diverse speaker prompts.", - id: "parler-tts/parler_tts_mini", + description: "An application that synthesizes emotional speech for diverse speaker prompts.", + id: "parler-tts/parler-tts-expresso", }, ], summary: From 0bcfcd74f2c1cba7bad83034c1432d1dbbd4231d Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Tue, 19 Nov 2024 09:18:13 +0100 Subject: [PATCH 53/97] feat(hub): adding snapshot download method (#1038) ## Description We can now create a `snapshotDownload` method similator to the `snapshot_download` of the PY lib[^1], clone to the cache (only cache supported for now) a repository (either model, space or dataset) [^1]: https://huggingface.co/docs/huggingface_hub/en/guides/download#download-an-entire-repository ## Related issues/PR With the amazing help of @coyotte508 we were able to merge the following changes - https://github.com/huggingface/huggingface.js/pull/1034 - https://github.com/huggingface/huggingface.js/pull/1031 - https://github.com/huggingface/huggingface.js/pull/999 Which allow this PR to provide a python compliant clone of a hugging face repository to the cache directory. ## Testing - [x] unit tests are covering the new feature **Manually** ```ts await snapshotDownload({ repo: { name: 'OuteAI/OuteTTS-0.1-350M', type: 'model', }, }); ``` assert using the `huggingface-cli` tool (python) ``` $: huggingface-cli scan-cache REPO ID REPO TYPE SIZE ON DISK NB FILES LAST_ACCESSED LAST_MODIFIED REFS LOCAL PATH ----------------------------------- --------- ------------ -------- ----------------- ----------------- ---- ---------------------------------------------------------------------------------- OuteAI/OuteTTS-0.1-350M model 731.6M 14 5 minutes ago 5 minutes ago main /home/axel7083/.cache/huggingface/hub/models--OuteAI--OuteTTS-0.1-350M ``` --------- Co-authored-by: Eliott C. --- packages/hub/README.md | 39 ++- packages/hub/package.json | 1 + packages/hub/src/lib/index.ts | 1 + .../hub/src/lib/snapshot-download.spec.ts | 275 ++++++++++++++++++ packages/hub/src/lib/snapshot-download.ts | 124 ++++++++ packages/hub/vitest-browser.config.mts | 8 +- 6 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 packages/hub/src/lib/snapshot-download.spec.ts create mode 100644 packages/hub/src/lib/snapshot-download.ts diff --git a/packages/hub/README.md b/packages/hub/README.md index c9a650a5c..3d87c15dc 100644 --- a/packages/hub/README.md +++ b/packages/hub/README.md @@ -117,6 +117,10 @@ Checkout the demo: https://huggingface.co/spaces/huggingfacejs/client-side-oauth The `@huggingface/hub` package provide basic capabilities to scan the cache directory. Learn more about [Manage huggingface_hub cache-system](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache). +### `scanCacheDir` + +You can get the list of cached repositories using the `scanCacheDir` function. + ```ts import { scanCacheDir } from "@huggingface/hub"; @@ -124,7 +128,40 @@ const result = await scanCacheDir(); console.log(result); ``` -Note that the cache directory is created and used only by the Python and Rust libraries. Downloading files using the `@huggingface/hub` package won't use the cache directory. +Note: this does not work in the browser + +### `downloadFileToCacheDir` + +You can cache a file of a repository using the `downloadFileToCacheDir` function. + +```ts +import { downloadFileToCacheDir } from "@huggingface/hub"; + +const file = await downloadFileToCacheDir({ + repo: 'foo/bar', + path: 'README.md' +}); + +console.log(file); +``` +Note: this does not work in the browser + +### `snapshotDownload` + +You can download an entire repository at a given revision in the cache directory using the `snapshotDownload` function. + +```ts +import { snapshotDownload } from "@huggingface/hub"; + +const directory = await snapshotDownload({ + repo: 'foo/bar', +}); + +console.log(directory); +``` +The code use internally the `downloadFileToCacheDir` function. + +Note: this does not work in the browser ## Performance considerations diff --git a/packages/hub/package.json b/packages/hub/package.json index 04486821d..9e84de2c1 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -22,6 +22,7 @@ "./src/utils/FileBlob.ts": false, "./src/lib/cache-management.ts": false, "./src/lib/download-file-to-cache-dir.ts": false, + "./src/lib/snapshot-download.ts": false, "./dist/index.js": "./dist/browser/index.js", "./dist/index.mjs": "./dist/browser/index.mjs" }, diff --git a/packages/hub/src/lib/index.ts b/packages/hub/src/lib/index.ts index c2a2fbe06..24e239bdc 100644 --- a/packages/hub/src/lib/index.ts +++ b/packages/hub/src/lib/index.ts @@ -21,6 +21,7 @@ export * from "./oauth-handle-redirect"; export * from "./oauth-login-url"; export * from "./parse-safetensors-metadata"; export * from "./paths-info"; +export * from "./snapshot-download"; export * from "./space-info"; export * from "./upload-file"; export * from "./upload-files"; diff --git a/packages/hub/src/lib/snapshot-download.spec.ts b/packages/hub/src/lib/snapshot-download.spec.ts new file mode 100644 index 000000000..0c44cc842 --- /dev/null +++ b/packages/hub/src/lib/snapshot-download.spec.ts @@ -0,0 +1,275 @@ +import { expect, test, describe, vi, beforeEach } from "vitest"; +import { dirname, join } from "node:path"; +import { mkdir, writeFile } from "node:fs/promises"; +import { getHFHubCachePath } from "./cache-management"; +import { downloadFileToCacheDir } from "./download-file-to-cache-dir"; +import { snapshotDownload } from "./snapshot-download"; +import type { ListFileEntry } from "./list-files"; +import { listFiles } from "./list-files"; +import { modelInfo } from "./model-info"; +import type { ModelEntry } from "./list-models"; +import type { ApiModelInfo } from "../types/api/api-model"; +import { datasetInfo } from "./dataset-info"; +import type { DatasetEntry } from "./list-datasets"; +import type { ApiDatasetInfo } from "../types/api/api-dataset"; +import { spaceInfo } from "./space-info"; +import type { SpaceEntry } from "./list-spaces"; +import type { ApiSpaceInfo } from "../types/api/api-space"; + +vi.mock("node:fs/promises", () => ({ + writeFile: vi.fn(), + mkdir: vi.fn(), +})); + +vi.mock("./space-info", () => ({ + spaceInfo: vi.fn(), +})); + +vi.mock("./dataset-info", () => ({ + datasetInfo: vi.fn(), +})); + +vi.mock("./model-info", () => ({ + modelInfo: vi.fn(), +})); + +vi.mock("./list-files", () => ({ + listFiles: vi.fn(), +})); + +vi.mock("./download-file-to-cache-dir", () => ({ + downloadFileToCacheDir: vi.fn(), +})); + +const DUMMY_SHA = "dummy-sha"; + +// utility method to transform an array of ListFileEntry to an AsyncGenerator +async function* toAsyncGenerator(content: ListFileEntry[]): AsyncGenerator { + for (const entry of content) { + yield Promise.resolve(entry); + } +} + +beforeEach(() => { + vi.resetAllMocks(); + vi.mocked(listFiles).mockReturnValue(toAsyncGenerator([])); + + // mock repo info + vi.mocked(modelInfo).mockResolvedValue({ + sha: DUMMY_SHA, + } as ModelEntry & ApiModelInfo); + vi.mocked(datasetInfo).mockResolvedValue({ + sha: DUMMY_SHA, + } as DatasetEntry & ApiDatasetInfo); + vi.mocked(spaceInfo).mockResolvedValue({ + sha: DUMMY_SHA, + } as SpaceEntry & ApiSpaceInfo); +}); + +describe("snapshotDownload", () => { + test("empty AsyncGenerator should not call downloadFileToCacheDir", async () => { + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + }); + + expect(downloadFileToCacheDir).not.toHaveBeenCalled(); + }); + + test("repo type model should use modelInfo", async () => { + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "model", + }, + }); + expect(modelInfo).toHaveBeenCalledOnce(); + expect(modelInfo).toHaveBeenCalledWith({ + name: "foo/bar", + additionalFields: ["sha"], + revision: "main", + repo: { + name: "foo/bar", + type: "model", + }, + }); + }); + + test("repo type dataset should use datasetInfo", async () => { + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "dataset", + }, + }); + expect(datasetInfo).toHaveBeenCalledOnce(); + expect(datasetInfo).toHaveBeenCalledWith({ + name: "foo/bar", + additionalFields: ["sha"], + revision: "main", + repo: { + name: "foo/bar", + type: "dataset", + }, + }); + }); + + test("repo type space should use spaceInfo", async () => { + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + }); + expect(spaceInfo).toHaveBeenCalledOnce(); + expect(spaceInfo).toHaveBeenCalledWith({ + name: "foo/bar", + additionalFields: ["sha"], + revision: "main", + repo: { + name: "foo/bar", + type: "space", + }, + }); + }); + + test("commitHash should be saved to ref folder", async () => { + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + revision: "dummy-revision", + }); + + // cross-platform testing + const expectedPath = join(getHFHubCachePath(), "spaces--foo--bar", "refs", "dummy-revision"); + expect(mkdir).toHaveBeenCalledWith(dirname(expectedPath), { recursive: true }); + expect(writeFile).toHaveBeenCalledWith(expectedPath, DUMMY_SHA); + }); + + test("directory ListFileEntry should mkdir it", async () => { + vi.mocked(listFiles).mockReturnValue( + toAsyncGenerator([ + { + oid: "dummy-etag", + type: "directory", + path: "potatoes", + size: 0, + lastCommit: { + date: new Date().toISOString(), + id: DUMMY_SHA, + title: "feat: best commit", + }, + }, + ]) + ); + + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + }); + + // cross-platform testing + const expectedPath = join(getHFHubCachePath(), "spaces--foo--bar", "snapshots", DUMMY_SHA, "potatoes"); + expect(mkdir).toHaveBeenCalledWith(expectedPath, { recursive: true }); + }); + + test("files in ListFileEntry should download them", async () => { + const entries: ListFileEntry[] = Array.from({ length: 10 }, (_, i) => ({ + oid: `dummy-etag-${i}`, + type: "file", + path: `file-${i}.txt`, + size: i, + lastCommit: { + date: new Date().toISOString(), + id: DUMMY_SHA, + title: "feat: best commit", + }, + })); + vi.mocked(listFiles).mockReturnValue(toAsyncGenerator(entries)); + + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + }); + + for (const entry of entries) { + expect(downloadFileToCacheDir).toHaveBeenCalledWith( + expect.objectContaining({ + repo: { + name: "foo/bar", + type: "space", + }, + path: entry.path, + revision: DUMMY_SHA, + }) + ); + } + }); + + test("custom params should be propagated", async () => { + // fetch mock + const fetchMock: typeof fetch = vi.fn(); + const hubMock = "https://foor.bar"; + const accessTokenMock = "dummy-access-token"; + + vi.mocked(listFiles).mockReturnValue( + toAsyncGenerator([ + { + oid: `dummy-etag`, + type: "file", + path: `file.txt`, + size: 10, + lastCommit: { + date: new Date().toISOString(), + id: DUMMY_SHA, + title: "feat: best commit", + }, + }, + ]) + ); + + await snapshotDownload({ + repo: { + name: "foo/bar", + type: "space", + }, + hubUrl: hubMock, + fetch: fetchMock, + accessToken: accessTokenMock, + }); + + expect(spaceInfo).toHaveBeenCalledWith( + expect.objectContaining({ + fetch: fetchMock, + hubUrl: hubMock, + accessToken: accessTokenMock, + }) + ); + + // list files should receive custom fetch + expect(listFiles).toHaveBeenCalledWith( + expect.objectContaining({ + fetch: fetchMock, + hubUrl: hubMock, + accessToken: accessTokenMock, + }) + ); + + // download file to cache should receive custom fetch + expect(downloadFileToCacheDir).toHaveBeenCalledWith( + expect.objectContaining({ + fetch: fetchMock, + hubUrl: hubMock, + accessToken: accessTokenMock, + }) + ); + }); +}); diff --git a/packages/hub/src/lib/snapshot-download.ts b/packages/hub/src/lib/snapshot-download.ts new file mode 100644 index 000000000..b3e30c13f --- /dev/null +++ b/packages/hub/src/lib/snapshot-download.ts @@ -0,0 +1,124 @@ +import type { CredentialsParams, RepoDesignation } from "../types/public"; +import { listFiles } from "./list-files"; +import { getHFHubCachePath, getRepoFolderName } from "./cache-management"; +import { spaceInfo } from "./space-info"; +import { datasetInfo } from "./dataset-info"; +import { modelInfo } from "./model-info"; +import { toRepoId } from "../utils/toRepoId"; +import { join, dirname } from "node:path"; +import { mkdir, writeFile } from "node:fs/promises"; +import { downloadFileToCacheDir } from "./download-file-to-cache-dir"; + +export const DEFAULT_REVISION = "main"; + +/** + * Downloads an entire repository at a given revision in the cache directory {@link getHFHubCachePath}. + * You can list all cached repositories using {@link scanCachedRepo} + * @remarks It uses internally {@link downloadFileToCacheDir}. + */ +export async function snapshotDownload( + params: { + repo: RepoDesignation; + cacheDir?: string; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + * + * @default "main" + */ + revision?: string; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise { + let cacheDir: string; + if (params.cacheDir) { + cacheDir = params.cacheDir; + } else { + cacheDir = getHFHubCachePath(); + } + + let revision: string; + if (params.revision) { + revision = params.revision; + } else { + revision = DEFAULT_REVISION; + } + + const repoId = toRepoId(params.repo); + + // get repository revision value (sha) + let repoInfo: { sha: string }; + switch (repoId.type) { + case "space": + repoInfo = await spaceInfo({ + ...params, + name: repoId.name, + additionalFields: ["sha"], + revision: revision, + }); + break; + case "dataset": + repoInfo = await datasetInfo({ + ...params, + name: repoId.name, + additionalFields: ["sha"], + revision: revision, + }); + break; + case "model": + repoInfo = await modelInfo({ + ...params, + name: repoId.name, + additionalFields: ["sha"], + revision: revision, + }); + break; + default: + throw new Error(`invalid repository type ${repoId.type}`); + } + + const commitHash: string = repoInfo.sha; + + // get storage folder + const storageFolder = join(cacheDir, getRepoFolderName(repoId)); + const snapshotFolder = join(storageFolder, "snapshots", commitHash); + + // if passed revision is not identical to commit_hash + // then revision has to be a branch name or tag name. + // In that case store a ref. + if (revision !== commitHash) { + const refPath = join(storageFolder, "refs", revision); + await mkdir(dirname(refPath), { recursive: true }); + await writeFile(refPath, commitHash); + } + + const cursor = listFiles({ + ...params, + repo: params.repo, + recursive: true, + revision: repoInfo.sha, + }); + + for await (const entry of cursor) { + switch (entry.type) { + case "file": + await downloadFileToCacheDir({ + ...params, + path: entry.path, + revision: commitHash, + cacheDir: cacheDir, + }); + break; + case "directory": + await mkdir(join(snapshotFolder, entry.path), { recursive: true }); + break; + default: + throw new Error(`unknown entry type: ${entry.type}`); + } + } + + return snapshotFolder; +} diff --git a/packages/hub/vitest-browser.config.mts b/packages/hub/vitest-browser.config.mts index 60fcbfbfc..db22fb67c 100644 --- a/packages/hub/vitest-browser.config.mts +++ b/packages/hub/vitest-browser.config.mts @@ -2,6 +2,12 @@ import { configDefaults, defineConfig } from "vitest/config"; export default defineConfig({ test: { - exclude: [...configDefaults.exclude, "src/utils/FileBlob.spec.ts", "src/lib/cache-management.spec.ts", "src/lib/download-file-to-cache-dir.spec.ts"], + exclude: [ + ...configDefaults.exclude, + "src/utils/FileBlob.spec.ts", + "src/lib/cache-management.spec.ts", + "src/lib/download-file-to-cache-dir.spec.ts", + "src/lib/snapshot-download.spec.ts", + ], }, }); From c54d745fda30bdee5e54a2a71fc88ce3ea16c5f5 Mon Sep 17 00:00:00 2001 From: Lucain Date: Tue, 19 Nov 2024 10:38:00 +0100 Subject: [PATCH 54/97] fix lint (#1042) --- packages/tasks/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tasks/src/index.ts b/packages/tasks/src/index.ts index f11661a13..c350fecd2 100644 --- a/packages/tasks/src/index.ts +++ b/packages/tasks/src/index.ts @@ -51,7 +51,6 @@ export * from "./gguf.js"; export { snippets }; export type { InferenceSnippet } from "./snippets/index.js"; - export { SKUS, DEFAULT_MEMORY_OPTIONS } from "./hardware.js"; export type { HardwareSpec, SkuType } from "./hardware.js"; export { LOCAL_APPS } from "./local-apps.js"; From 32b26e2c7e0824d7ab529a1e8aa02046e86920d8 Mon Sep 17 00:00:00 2001 From: lewington Date: Tue, 19 Nov 2024 20:42:27 +1100 Subject: [PATCH 55/97] add CLIP-ViT-L-scope (#1022) Co-authored-by: Lucain Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index c4bda8222..9118a1eda 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -212,6 +212,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { repoUrl: "https://github.com/cartesia-ai/cartesia_mlx", snippets: snippets.cartesia_mlx, }, + clipscope: { + prettyLabel: "clipscope", + repoName: "clipscope", + repoUrl: "https://github.com/Lewington-pitsos/clipscope", + filter: false, + countDownloads: `path_extension:"pt"`, + }, cotracker: { prettyLabel: "CoTracker", repoName: "CoTracker", From f0389a62c8bd7e49b76352f5438082aeb929c656 Mon Sep 17 00:00:00 2001 From: machineuser Date: Tue, 19 Nov 2024 09:46:23 +0000 Subject: [PATCH 56/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index e9e64c0bf..367447ca0 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.3", + "version": "0.13.4", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 04fa3bb8f2bcea879e7fa73e02e18a39d7845efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9lina?= Date: Wed, 20 Nov 2024 10:37:04 +0100 Subject: [PATCH 57/97] Tasks: add `function_to_apply`'s docstring for classification tasks (#1043) This PR adds missing parameter description for `function_to_apply`. this documentation is required since huggingface_hub's `InferenceClient` documentation is automatically generated from the specs defined here (See [huggingface_hub/.github/workflows/update-inference-types.yaml](https://github.com/huggingface/huggingface_hub/blob/main/.github/workflows/update-inference-types.yaml) for more details). Note: the description was not technically missing since it's already available in `ClassificationOutputTransform`'s description, but it wasn't being properly inferred for the `function_to_apply` property. --- packages/tasks/src/tasks/audio-classification/inference.ts | 3 +++ packages/tasks/src/tasks/audio-classification/spec/input.json | 3 ++- packages/tasks/src/tasks/image-classification/inference.ts | 3 +++ packages/tasks/src/tasks/image-classification/spec/input.json | 3 ++- packages/tasks/src/tasks/text-classification/inference.ts | 3 +++ packages/tasks/src/tasks/text-classification/spec/input.json | 3 ++- packages/tasks/src/tasks/video-classification/inference.ts | 3 +++ packages/tasks/src/tasks/video-classification/spec/input.json | 3 ++- 8 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/tasks/src/tasks/audio-classification/inference.ts b/packages/tasks/src/tasks/audio-classification/inference.ts index b8ed3f50f..136d8420e 100644 --- a/packages/tasks/src/tasks/audio-classification/inference.ts +++ b/packages/tasks/src/tasks/audio-classification/inference.ts @@ -24,6 +24,9 @@ export interface AudioClassificationInput { * Additional inference parameters for Audio Classification */ export interface AudioClassificationParameters { + /** + * The function to apply to the model outputs in order to retrieve the scores. + */ function_to_apply?: ClassificationOutputTransform; /** * When specified, limits the output to the top K most probable classes. diff --git a/packages/tasks/src/tasks/audio-classification/spec/input.json b/packages/tasks/src/tasks/audio-classification/spec/input.json index 0bfeb69cd..38f06d815 100644 --- a/packages/tasks/src/tasks/audio-classification/spec/input.json +++ b/packages/tasks/src/tasks/audio-classification/spec/input.json @@ -22,7 +22,8 @@ "properties": { "function_to_apply": { "title": "AudioClassificationOutputTransform", - "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform" + "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform", + "description": "The function to apply to the model outputs in order to retrieve the scores." }, "top_k": { "type": "integer", diff --git a/packages/tasks/src/tasks/image-classification/inference.ts b/packages/tasks/src/tasks/image-classification/inference.ts index bd56a7d31..917670476 100644 --- a/packages/tasks/src/tasks/image-classification/inference.ts +++ b/packages/tasks/src/tasks/image-classification/inference.ts @@ -24,6 +24,9 @@ export interface ImageClassificationInput { * Additional inference parameters for Image Classification */ export interface ImageClassificationParameters { + /** + * The function to apply to the model outputs in order to retrieve the scores. + */ function_to_apply?: ClassificationOutputTransform; /** * When specified, limits the output to the top K most probable classes. diff --git a/packages/tasks/src/tasks/image-classification/spec/input.json b/packages/tasks/src/tasks/image-classification/spec/input.json index cf0b30ec5..09d53a346 100644 --- a/packages/tasks/src/tasks/image-classification/spec/input.json +++ b/packages/tasks/src/tasks/image-classification/spec/input.json @@ -22,7 +22,8 @@ "properties": { "function_to_apply": { "title": "ImageClassificationOutputTransform", - "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform" + "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform", + "description": "The function to apply to the model outputs in order to retrieve the scores." }, "top_k": { "type": "integer", diff --git a/packages/tasks/src/tasks/text-classification/inference.ts b/packages/tasks/src/tasks/text-classification/inference.ts index dc9136902..82ab270ea 100644 --- a/packages/tasks/src/tasks/text-classification/inference.ts +++ b/packages/tasks/src/tasks/text-classification/inference.ts @@ -23,6 +23,9 @@ export interface TextClassificationInput { * Additional inference parameters for Text Classification */ export interface TextClassificationParameters { + /** + * The function to apply to the model outputs in order to retrieve the scores. + */ function_to_apply?: ClassificationOutputTransform; /** * When specified, limits the output to the top K most probable classes. diff --git a/packages/tasks/src/tasks/text-classification/spec/input.json b/packages/tasks/src/tasks/text-classification/spec/input.json index 3bfdeaf6b..0b05d59a5 100644 --- a/packages/tasks/src/tasks/text-classification/spec/input.json +++ b/packages/tasks/src/tasks/text-classification/spec/input.json @@ -22,7 +22,8 @@ "properties": { "function_to_apply": { "title": "TextClassificationOutputTransform", - "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform" + "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform", + "description": "The function to apply to the model outputs in order to retrieve the scores." }, "top_k": { "type": "integer", diff --git a/packages/tasks/src/tasks/video-classification/inference.ts b/packages/tasks/src/tasks/video-classification/inference.ts index 6615b8ddc..e50e0c299 100644 --- a/packages/tasks/src/tasks/video-classification/inference.ts +++ b/packages/tasks/src/tasks/video-classification/inference.ts @@ -27,6 +27,9 @@ export interface VideoClassificationParameters { * The sampling rate used to select frames from the video. */ frame_sampling_rate?: number; + /** + * The function to apply to the model outputs in order to retrieve the scores. + */ function_to_apply?: ClassificationOutputTransform; /** * The number of sampled frames to consider for classification. diff --git a/packages/tasks/src/tasks/video-classification/spec/input.json b/packages/tasks/src/tasks/video-classification/spec/input.json index 1fb58e278..8bcef7f75 100644 --- a/packages/tasks/src/tasks/video-classification/spec/input.json +++ b/packages/tasks/src/tasks/video-classification/spec/input.json @@ -21,7 +21,8 @@ "properties": { "function_to_apply": { "title": "TextClassificationOutputTransform", - "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform" + "$ref": "/inference/schemas/common-definitions.json#/definitions/ClassificationOutputTransform", + "description": "The function to apply to the model outputs in order to retrieve the scores." }, "num_frames": { "type": "integer", From f83bbe602748b298c16c635d809b5ea476bf2e43 Mon Sep 17 00:00:00 2001 From: Mishig Date: Wed, 20 Nov 2024 10:44:11 +0100 Subject: [PATCH 58/97] [Local App Snippet] support non conversational LLMs (#954) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Most GGUF files on the hub are insutrct/conversational. However, not all of them. Previously, local app snippets assumed that all GGUFs are insutrct/conversational. ### vLLM https://huggingface.co/meta-llama/Llama-3.2-3B?local-app=vllm ```json mishig@machine:~$ curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "meta-llama/Llama-3.2-3B", "prompt": "Once upon a time", "max_tokens": 150, "temperature": 0.5 }' {"id":"cmpl-157aad50ba6d45a5a7e2641a3c8157dd","object":"text_completion","created":1728293162,"model":"meta-llama/Llama-3.2-3B","choices":[{"index":0,"text":" there was a man who was very generous and kind to everyone. He was a good man and a good person. One day he was walking down the street and he saw a man who was very poor and starving. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking. The man was so hungry that he was crying and shaking","logprobs":null,"finish_reason":"length","stop_reason":null,"prompt_logprobs":null}],"usage":{"prompt_tokens":5,"total_tokens":155,"completion_tokens":150}} ``` ### llama.cpp https://huggingface.co/mlabonne/gemma-2b-GGUF?local-app=llama.cpp ``` llama-cli \ --hf-repo "mlabonne/gemma-2b-GGUF" \ --hf-file gemma-2b.Q2_K.gguf \ -p "Once upon a time " ``` ### llama-cpp-python ```python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="mlabonne/gemma-2b-GGUF", filename="gemma-2b.Q2_K.gguf", ) output = llm( "Once upon a time ", max_tokens=512, echo=True ) print(output) ``` --------- Co-authored-by: vb Co-authored-by: Victor Muštar --- packages/tasks/src/local-apps.spec.ts | 123 ++++++++++++++++++ packages/tasks/src/local-apps.ts | 55 +++++--- .../src/model-libraries-snippets.spec.ts | 54 ++++++++ .../tasks/src/model-libraries-snippets.ts | 35 +++-- 4 files changed, 238 insertions(+), 29 deletions(-) create mode 100644 packages/tasks/src/local-apps.spec.ts create mode 100644 packages/tasks/src/model-libraries-snippets.spec.ts diff --git a/packages/tasks/src/local-apps.spec.ts b/packages/tasks/src/local-apps.spec.ts new file mode 100644 index 000000000..23806f668 --- /dev/null +++ b/packages/tasks/src/local-apps.spec.ts @@ -0,0 +1,123 @@ +import { describe, expect, it } from "vitest"; +import { LOCAL_APPS } from "./local-apps.js"; +import type { ModelData } from "./model-data.js"; + +describe("local-apps", () => { + it("llama.cpp conversational", async () => { + const { snippet: snippetFunc } = LOCAL_APPS["llama.cpp"]; + const model: ModelData = { + id: "bartowski/Llama-3.2-3B-Instruct-GGUF", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetFunc(model); + + expect(snippet[0].content).toEqual(`# Load and run the model: +llama-cli \\ + --hf-repo "bartowski/Llama-3.2-3B-Instruct-GGUF" \\ + --hf-file {{GGUF_FILE}} \\ + -p "You are a helpful assistant" \\ + --conversation`); + }); + + it("llama.cpp non-conversational", async () => { + const { snippet: snippetFunc } = LOCAL_APPS["llama.cpp"]; + const model: ModelData = { + id: "mlabonne/gemma-2b-GGUF", + tags: [], + inference: "", + }; + const snippet = snippetFunc(model); + + expect(snippet[0].content).toEqual(`# Load and run the model: +llama-cli \\ + --hf-repo "mlabonne/gemma-2b-GGUF" \\ + --hf-file {{GGUF_FILE}} \\ + -p "Once upon a time,"`); + }); + + it("vLLM conversational llm", async () => { + const { snippet: snippetFunc } = LOCAL_APPS["vllm"]; + const model: ModelData = { + id: "meta-llama/Llama-3.2-3B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetFunc(model); + + expect((snippet[0].content as string[]).join("\n")).toEqual(`# Load and run the model: +vllm serve "meta-llama/Llama-3.2-3B-Instruct" +# Call the server using curl: +curl -X POST "http://localhost:8000/v1/chat/completions" \\ + -H "Content-Type: application/json" \\ + --data '{ + "model": "meta-llama/Llama-3.2-3B-Instruct", + "messages": [ + { + "role": "user", + "content": "What is the capital of France?" + } + ] + }'`); + }); + + it("vLLM non-conversational llm", async () => { + const { snippet: snippetFunc } = LOCAL_APPS["vllm"]; + const model: ModelData = { + id: "meta-llama/Llama-3.2-3B", + tags: [""], + inference: "", + }; + const snippet = snippetFunc(model); + + expect((snippet[0].content as string[]).join("\n")).toEqual(`# Load and run the model: +vllm serve "meta-llama/Llama-3.2-3B" +# Call the server using curl: +curl -X POST "http://localhost:8000/v1/completions" \\ + -H "Content-Type: application/json" \\ + --data '{ + "model": "meta-llama/Llama-3.2-3B", + "prompt": "Once upon a time,", + "max_tokens": 512, + "temperature": 0.5 + }'`); + }); + + it("vLLM conversational vlm", async () => { + const { snippet: snippetFunc } = LOCAL_APPS["vllm"]; + const model: ModelData = { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }; + const snippet = snippetFunc(model); + + expect((snippet[0].content as string[]).join("\n")).toEqual(`# Load and run the model: +vllm serve "meta-llama/Llama-3.2-11B-Vision-Instruct" +# Call the server using curl: +curl -X POST "http://localhost:8000/v1/chat/completions" \\ + -H "Content-Type: application/json" \\ + --data '{ + "model": "meta-llama/Llama-3.2-11B-Vision-Instruct", + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ] + }'`); + }); +}); diff --git a/packages/tasks/src/local-apps.ts b/packages/tasks/src/local-apps.ts index edc7e64fd..2249183a4 100644 --- a/packages/tasks/src/local-apps.ts +++ b/packages/tasks/src/local-apps.ts @@ -1,6 +1,9 @@ import { parseGGUFQuantLabel } from "./gguf.js"; import type { ModelData } from "./model-data.js"; import type { PipelineType } from "./pipelines.js"; +import { stringifyMessages } from "./snippets/common.js"; +import { getModelInputSnippet } from "./snippets/inputs.js"; +import type { ChatCompletionInputMessage } from "./tasks/index.js"; export interface LocalAppSnippet { /** @@ -92,15 +95,20 @@ function isMlxModel(model: ModelData) { } const snippetLlamacpp = (model: ModelData, filepath?: string): LocalAppSnippet[] => { - const command = (binary: string) => - [ + const command = (binary: string) => { + const snippet = [ "# Load and run the model:", `${binary} \\`, ` --hf-repo "${model.id}" \\`, ` --hf-file ${filepath ?? "{{GGUF_FILE}}"} \\`, - ' -p "You are a helpful assistant" \\', - " --conversation", - ].join("\n"); + ` -p "${model.tags.includes("conversational") ? "You are a helpful assistant" : "Once upon a time,"}"`, + ]; + if (model.tags.includes("conversational")) { + snippet[snippet.length - 1] += " \\"; + snippet.push(" --conversation"); + } + return snippet.join("\n"); + }; return [ { title: "Install from brew", @@ -178,22 +186,33 @@ const snippetLocalAI = (model: ModelData, filepath?: string): LocalAppSnippet[] }; const snippetVllm = (model: ModelData): LocalAppSnippet[] => { - const runCommand = [ - "# Call the server using curl:", - `curl -X POST "http://localhost:8000/v1/chat/completions" \\`, - ` -H "Content-Type: application/json" \\`, - ` --data '{`, - ` "model": "${model.id}",`, - ` "messages": [`, - ` {"role": "user", "content": "Hello!"}`, - ` ]`, - ` }'`, - ]; + const messages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; + const runCommandInstruct = `# Call the server using curl: +curl -X POST "http://localhost:8000/v1/chat/completions" \\ + -H "Content-Type: application/json" \\ + --data '{ + "model": "${model.id}", + "messages": ${stringifyMessages(messages, { + indent: "\t\t", + attributeKeyQuotes: true, + customContentEscaper: (str) => str.replace(/'/g, "'\\''"), + })} + }'`; + const runCommandNonInstruct = `# Call the server using curl: +curl -X POST "http://localhost:8000/v1/completions" \\ + -H "Content-Type: application/json" \\ + --data '{ + "model": "${model.id}", + "prompt": "Once upon a time,", + "max_tokens": 512, + "temperature": 0.5 + }'`; + const runCommand = model.tags.includes("conversational") ? runCommandInstruct : runCommandNonInstruct; return [ { title: "Install from pip", setup: ["# Install vLLM from pip:", "pip install vllm"].join("\n"), - content: [`# Load and run the model:\nvllm serve "${model.id}"`, runCommand.join("\n")], + content: [`# Load and run the model:\nvllm serve "${model.id}"`, runCommand], }, { title: "Use Docker images", @@ -210,7 +229,7 @@ const snippetVllm = (model: ModelData): LocalAppSnippet[] => { ].join("\n"), content: [ `# Load and run the model:\ndocker exec -it my_vllm_container bash -c "vllm serve ${model.id}"`, - runCommand.join("\n"), + runCommand, ], }, ]; diff --git a/packages/tasks/src/model-libraries-snippets.spec.ts b/packages/tasks/src/model-libraries-snippets.spec.ts new file mode 100644 index 000000000..fa87d8242 --- /dev/null +++ b/packages/tasks/src/model-libraries-snippets.spec.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest"; +import type { ModelData } from "./model-data.js"; +import { llama_cpp_python } from "./model-libraries-snippets.js"; + +describe("model-libraries-snippets", () => { + it("llama_cpp_python conversational", async () => { + const model: ModelData = { + id: "bartowski/Llama-3.2-3B-Instruct-GGUF", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }; + const snippet = llama_cpp_python(model); + + expect(snippet.join("\n")).toEqual(`from llama_cpp import Llama + +llm = Llama.from_pretrained( + repo_id="bartowski/Llama-3.2-3B-Instruct-GGUF", + filename="{{GGUF_FILE}}", +) + +llm.create_chat_completion( + messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } + ] +)`); + }); + + it("llama_cpp_python non-conversational", async () => { + const model: ModelData = { + id: "mlabonne/gemma-2b-GGUF", + tags: [""], + inference: "", + }; + const snippet = llama_cpp_python(model); + + expect(snippet.join("\n")).toEqual(`from llama_cpp import Llama + +llm = Llama.from_pretrained( + repo_id="mlabonne/gemma-2b-GGUF", + filename="{{GGUF_FILE}}", +) + +output = llm( + "Once upon a time,", + max_tokens=512, + echo=True +) +print(output)`); + }); +}); diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index 523d1a245..bb6ac12c3 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -1,6 +1,9 @@ import type { ModelData } from "./model-data.js"; import type { WidgetExampleTextInput, WidgetExampleSentenceSimilarityInput } from "./widget-example.js"; import { LIBRARY_TASK_MAPPING } from "./library-to-tasks.js"; +import { getModelInputSnippet } from "./snippets/inputs.js"; +import type { ChatCompletionInputMessage } from "./tasks/index.js"; +import { stringifyMessages } from "./snippets/common.js"; const TAG_CUSTOM_CODE = "custom_code"; @@ -418,23 +421,33 @@ model = keras_hub.models.CausalLM.from_preset("hf://${model.id}", dtype="bfloat1 `, ]; -export const llama_cpp_python = (model: ModelData): string[] => [ - `from llama_cpp import Llama +export const llama_cpp_python = (model: ModelData): string[] => { + const snippets = [ + `from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="${model.id}", filename="{{GGUF_FILE}}", ) +`, + ]; -llm.create_chat_completion( - messages = [ - { - "role": "user", - "content": "What is the capital of France?" - } - ] -)`, -]; + if (model.tags.includes("conversational")) { + const messages = getModelInputSnippet(model) as ChatCompletionInputMessage[]; + snippets.push(`llm.create_chat_completion( + messages = ${stringifyMessages(messages, { attributeKeyQuotes: true, indent: "\t" })} +)`); + } else { + snippets.push(`output = llm( + "Once upon a time,", + max_tokens=512, + echo=True +) +print(output)`); + } + + return snippets; +}; export const tf_keras = (model: ModelData): string[] => [ `# Note: 'keras<3.x' or 'tf_keras' must be installed (legacy) From 0b1ecd52ff840784cac73c8be4fcc5cd9e89298d Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 20 Nov 2024 09:45:01 +0000 Subject: [PATCH 59/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 367447ca0..a02c29488 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.4", + "version": "0.13.5", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 21158d74b3935ad579748bde18b55fcfeec368bc Mon Sep 17 00:00:00 2001 From: Dmitry Starkov <21260939+starkdmi@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:47:48 +0300 Subject: [PATCH 60/97] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Updat?= =?UTF-8?q?e=20Apple=20Silicon=20hardware,=20add=20M4=20series=20(#1044)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed: - M2 Pro ~6.8 (FP32, 19 cores) - M3 4.1 (FP32, 10 cores) - M3 Pro 6.39-7.4 (FP32, 18 cores) New: - M4 4.6 (FP32, 10 cores) - M4 Pro 9.2 (FP32, 20 cores) - M4 Max 18.4 (FP32, 40 cores) --- packages/tasks/src/hardware.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/tasks/src/hardware.ts b/packages/tasks/src/hardware.ts index 2bae4bdb6..efde8177b 100644 --- a/packages/tasks/src/hardware.ts +++ b/packages/tasks/src/hardware.ts @@ -452,7 +452,7 @@ export const SKUS = { memory: [8, 16, 24], }, "Apple M2 Pro": { - tflops: 13.6, + tflops: 6.8, memory: [16, 24, 32], }, "Apple M2 Max": { @@ -464,17 +464,29 @@ export const SKUS = { memory: [64, 96, 128, 192], }, "Apple M3": { - tflops: 2.84, + tflops: 4.1, memory: [8, 16, 24], }, "Apple M3 Pro": { - tflops: 14, + tflops: 7.4, memory: [18, 36], }, "Apple M3 Max": { tflops: 14.2, memory: [36, 48, 64, 96, 128], }, + "Apple M4": { + tflops: 4.6, + memory: [16, 24, 32], + }, + "Apple M4 Pro": { + tflops: 9.2, + memory: [24, 48], + }, + "Apple M4 Max": { + tflops: 18.4, + memory: [36, 48, 64, 128], + }, }, }, } satisfies Record>>; From 0ebf911156598dcbbe2779bfc1ce8c5a233c0edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9lina?= Date: Thu, 21 Nov 2024 16:52:25 +0100 Subject: [PATCH 61/97] [Tasks] remove duplicate description in task parameter objects (#1045) this PR removes redundant description in task parameter classes definition while keeping it in the parameters field reference. this avoids duplicate documentation, see: [huggingface/huggingface_hub/pull/2664#discussion](https://github.com/huggingface/huggingface_hub/pull/2664#discussion_r1851713362) for more context. Note : `packages/tasks/src/tasks/{task_name/inference.ts` files are auto-generated. --- packages/tasks/src/tasks/audio-classification/inference.ts | 4 +--- .../tasks/src/tasks/audio-classification/spec/input.json | 3 +-- .../src/tasks/automatic-speech-recognition/inference.ts | 6 +----- .../src/tasks/automatic-speech-recognition/spec/input.json | 3 +-- packages/tasks/src/tasks/common-definitions.json | 1 - packages/tasks/src/tasks/depth-estimation/inference.ts | 2 +- packages/tasks/src/tasks/depth-estimation/spec/input.json | 3 +-- .../src/tasks/document-question-answering/inference.ts | 4 +--- .../src/tasks/document-question-answering/spec/input.json | 3 +-- packages/tasks/src/tasks/fill-mask/inference.ts | 4 +--- packages/tasks/src/tasks/fill-mask/spec/input.json | 3 +-- packages/tasks/src/tasks/image-classification/inference.ts | 4 +--- .../tasks/src/tasks/image-classification/spec/input.json | 3 +-- packages/tasks/src/tasks/image-segmentation/inference.ts | 4 +--- packages/tasks/src/tasks/image-segmentation/spec/input.json | 3 +-- packages/tasks/src/tasks/image-to-image/inference.ts | 4 +--- packages/tasks/src/tasks/image-to-image/spec/input.json | 3 +-- packages/tasks/src/tasks/image-to-text/inference.ts | 6 +----- packages/tasks/src/tasks/image-to-text/spec/input.json | 3 +-- packages/tasks/src/tasks/object-detection/inference.ts | 4 +--- packages/tasks/src/tasks/object-detection/spec/input.json | 3 +-- packages/tasks/src/tasks/placeholder/spec/input.json | 3 +-- packages/tasks/src/tasks/question-answering/inference.ts | 4 +--- packages/tasks/src/tasks/question-answering/spec/input.json | 3 +-- packages/tasks/src/tasks/sentence-similarity/inference.ts | 2 +- .../tasks/src/tasks/sentence-similarity/spec/input.json | 3 +-- packages/tasks/src/tasks/summarization/inference.ts | 4 +--- packages/tasks/src/tasks/summarization/spec/input.json | 3 +-- .../tasks/src/tasks/table-question-answering/inference.ts | 2 +- .../src/tasks/table-question-answering/spec/input.json | 3 +-- packages/tasks/src/tasks/text-classification/inference.ts | 4 +--- .../tasks/src/tasks/text-classification/spec/input.json | 3 +-- packages/tasks/src/tasks/text-to-audio/inference.ts | 6 +----- packages/tasks/src/tasks/text-to-audio/spec/input.json | 3 +-- packages/tasks/src/tasks/text-to-image/inference.ts | 4 +--- packages/tasks/src/tasks/text-to-image/spec/input.json | 3 +-- packages/tasks/src/tasks/text-to-speech/inference.ts | 6 +----- packages/tasks/src/tasks/text-to-speech/spec/input.json | 3 +-- packages/tasks/src/tasks/text2text-generation/inference.ts | 4 +--- .../tasks/src/tasks/text2text-generation/spec/input.json | 3 +-- packages/tasks/src/tasks/token-classification/inference.ts | 4 +--- .../tasks/src/tasks/token-classification/spec/input.json | 3 +-- packages/tasks/src/tasks/translation/inference.ts | 4 +--- packages/tasks/src/tasks/translation/spec/input.json | 3 +-- packages/tasks/src/tasks/video-classification/inference.ts | 4 +--- .../tasks/src/tasks/video-classification/spec/input.json | 3 +-- .../tasks/src/tasks/visual-question-answering/inference.ts | 4 +--- .../src/tasks/visual-question-answering/spec/input.json | 3 +-- .../tasks/src/tasks/zero-shot-classification/inference.ts | 4 +--- .../src/tasks/zero-shot-classification/spec/input.json | 3 +-- .../src/tasks/zero-shot-image-classification/inference.ts | 4 +--- .../tasks/zero-shot-image-classification/spec/input.json | 3 +-- .../tasks/src/tasks/zero-shot-object-detection/inference.ts | 4 +--- .../src/tasks/zero-shot-object-detection/spec/input.json | 3 +-- 54 files changed, 53 insertions(+), 135 deletions(-) diff --git a/packages/tasks/src/tasks/audio-classification/inference.ts b/packages/tasks/src/tasks/audio-classification/inference.ts index 136d8420e..9d3bfb1da 100644 --- a/packages/tasks/src/tasks/audio-classification/inference.ts +++ b/packages/tasks/src/tasks/audio-classification/inference.ts @@ -13,14 +13,12 @@ export interface AudioClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Audio Classification */ parameters?: AudioClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Audio Classification */ export interface AudioClassificationParameters { diff --git a/packages/tasks/src/tasks/audio-classification/spec/input.json b/packages/tasks/src/tasks/audio-classification/spec/input.json index 38f06d815..dc8036b9b 100644 --- a/packages/tasks/src/tasks/audio-classification/spec/input.json +++ b/packages/tasks/src/tasks/audio-classification/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Audio Classification", "$ref": "#/$defs/AudioClassificationParameters" } }, "$defs": { "AudioClassificationParameters": { "title": "AudioClassificationParameters", - "description": "Additional inference parameters for Audio Classification", "type": "object", "properties": { "function_to_apply": { diff --git a/packages/tasks/src/tasks/automatic-speech-recognition/inference.ts b/packages/tasks/src/tasks/automatic-speech-recognition/inference.ts index e1f1a8433..d105c16e8 100644 --- a/packages/tasks/src/tasks/automatic-speech-recognition/inference.ts +++ b/packages/tasks/src/tasks/automatic-speech-recognition/inference.ts @@ -14,15 +14,13 @@ export interface AutomaticSpeechRecognitionInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Automatic Speech Recognition */ parameters?: AutomaticSpeechRecognitionParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Automatic Speech Recognition */ export interface AutomaticSpeechRecognitionParameters { @@ -39,8 +37,6 @@ export interface AutomaticSpeechRecognitionParameters { /** * Parametrization of the text generation process - * - * Ad-hoc parametrization of the text generation process */ export interface GenerationParameters { /** diff --git a/packages/tasks/src/tasks/automatic-speech-recognition/spec/input.json b/packages/tasks/src/tasks/automatic-speech-recognition/spec/input.json index a028bb352..98f1bdf5b 100644 --- a/packages/tasks/src/tasks/automatic-speech-recognition/spec/input.json +++ b/packages/tasks/src/tasks/automatic-speech-recognition/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Automatic Speech Recognition", "$ref": "#/$defs/AutomaticSpeechRecognitionParameters" } }, "$defs": { "AutomaticSpeechRecognitionParameters": { "title": "AutomaticSpeechRecognitionParameters", - "description": "Additional inference parameters for Automatic Speech Recognition", "type": "object", "properties": { "return_timestamps": { diff --git a/packages/tasks/src/tasks/common-definitions.json b/packages/tasks/src/tasks/common-definitions.json index 03758a422..a9603fc06 100644 --- a/packages/tasks/src/tasks/common-definitions.json +++ b/packages/tasks/src/tasks/common-definitions.json @@ -26,7 +26,6 @@ }, "GenerationParameters": { "title": "GenerationParameters", - "description": "Ad-hoc parametrization of the text generation process", "type": "object", "properties": { "temperature": { diff --git a/packages/tasks/src/tasks/depth-estimation/inference.ts b/packages/tasks/src/tasks/depth-estimation/inference.ts index f873f9254..6b2cff1ff 100644 --- a/packages/tasks/src/tasks/depth-estimation/inference.ts +++ b/packages/tasks/src/tasks/depth-estimation/inference.ts @@ -13,7 +13,7 @@ export interface DepthEstimationInput { */ inputs: unknown; /** - * Additional inference parameters + * Additional inference parameters for Depth Estimation */ parameters?: { [key: string]: unknown }; [property: string]: unknown; diff --git a/packages/tasks/src/tasks/depth-estimation/spec/input.json b/packages/tasks/src/tasks/depth-estimation/spec/input.json index 2a4ecc71c..fb6c70bdd 100644 --- a/packages/tasks/src/tasks/depth-estimation/spec/input.json +++ b/packages/tasks/src/tasks/depth-estimation/spec/input.json @@ -9,14 +9,13 @@ "description": "The input image data" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Depth Estimation", "$ref": "#/$defs/DepthEstimationParameters" } }, "$defs": { "DepthEstimationParameters": { "title": "DepthEstimationParameters", - "description": "Additional inference parameters for Depth Estimation", "type": "object", "properties": {} } diff --git a/packages/tasks/src/tasks/document-question-answering/inference.ts b/packages/tasks/src/tasks/document-question-answering/inference.ts index 9c937b29a..8ec6b58a0 100644 --- a/packages/tasks/src/tasks/document-question-answering/inference.ts +++ b/packages/tasks/src/tasks/document-question-answering/inference.ts @@ -12,7 +12,7 @@ export interface DocumentQuestionAnsweringInput { */ inputs: DocumentQuestionAnsweringInputData; /** - * Additional inference parameters + * Additional inference parameters for Document Question Answering */ parameters?: DocumentQuestionAnsweringParameters; [property: string]: unknown; @@ -32,8 +32,6 @@ export interface DocumentQuestionAnsweringInputData { [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Document Question Answering */ export interface DocumentQuestionAnsweringParameters { diff --git a/packages/tasks/src/tasks/document-question-answering/spec/input.json b/packages/tasks/src/tasks/document-question-answering/spec/input.json index b017ce469..e04e53436 100644 --- a/packages/tasks/src/tasks/document-question-answering/spec/input.json +++ b/packages/tasks/src/tasks/document-question-answering/spec/input.json @@ -21,14 +21,13 @@ "required": ["image", "question"] }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Document Question Answering", "$ref": "#/$defs/DocumentQuestionAnsweringParameters" } }, "$defs": { "DocumentQuestionAnsweringParameters": { "title": "DocumentQuestionAnsweringParameters", - "description": "Additional inference parameters for Document Question Answering", "type": "object", "properties": { "doc_stride": { diff --git a/packages/tasks/src/tasks/fill-mask/inference.ts b/packages/tasks/src/tasks/fill-mask/inference.ts index 4d78ecd81..4f48bb55e 100644 --- a/packages/tasks/src/tasks/fill-mask/inference.ts +++ b/packages/tasks/src/tasks/fill-mask/inference.ts @@ -12,14 +12,12 @@ export interface FillMaskInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Fill Mask */ parameters?: FillMaskParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Fill Mask */ export interface FillMaskParameters { diff --git a/packages/tasks/src/tasks/fill-mask/spec/input.json b/packages/tasks/src/tasks/fill-mask/spec/input.json index cd3271e4a..a2ebaf13e 100644 --- a/packages/tasks/src/tasks/fill-mask/spec/input.json +++ b/packages/tasks/src/tasks/fill-mask/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Fill Mask", "$ref": "#/$defs/FillMaskParameters" } }, "$defs": { "FillMaskParameters": { "title": "FillMaskParameters", - "description": "Additional inference parameters for Fill Mask", "type": "object", "properties": { "top_k": { diff --git a/packages/tasks/src/tasks/image-classification/inference.ts b/packages/tasks/src/tasks/image-classification/inference.ts index 917670476..1f6fd103e 100644 --- a/packages/tasks/src/tasks/image-classification/inference.ts +++ b/packages/tasks/src/tasks/image-classification/inference.ts @@ -13,14 +13,12 @@ export interface ImageClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Image Classification */ parameters?: ImageClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Image Classification */ export interface ImageClassificationParameters { diff --git a/packages/tasks/src/tasks/image-classification/spec/input.json b/packages/tasks/src/tasks/image-classification/spec/input.json index 09d53a346..3e2bd13d4 100644 --- a/packages/tasks/src/tasks/image-classification/spec/input.json +++ b/packages/tasks/src/tasks/image-classification/spec/input.json @@ -10,14 +10,13 @@ "description": "The input image data as a base64-encoded string. If no `parameters` are provided, you can also provide the image data as a raw bytes payload." }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Image Classification", "$ref": "#/$defs/ImageClassificationParameters" } }, "$defs": { "ImageClassificationParameters": { "title": "ImageClassificationParameters", - "description": "Additional inference parameters for Image Classification", "type": "object", "properties": { "function_to_apply": { diff --git a/packages/tasks/src/tasks/image-segmentation/inference.ts b/packages/tasks/src/tasks/image-segmentation/inference.ts index 4ccd36e41..e299d0e67 100644 --- a/packages/tasks/src/tasks/image-segmentation/inference.ts +++ b/packages/tasks/src/tasks/image-segmentation/inference.ts @@ -13,14 +13,12 @@ export interface ImageSegmentationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Image Segmentation */ parameters?: ImageSegmentationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Image Segmentation */ export interface ImageSegmentationParameters { diff --git a/packages/tasks/src/tasks/image-segmentation/spec/input.json b/packages/tasks/src/tasks/image-segmentation/spec/input.json index 697f8959b..2023f93f1 100644 --- a/packages/tasks/src/tasks/image-segmentation/spec/input.json +++ b/packages/tasks/src/tasks/image-segmentation/spec/input.json @@ -10,14 +10,13 @@ "description": "The input image data as a base64-encoded string. If no `parameters` are provided, you can also provide the image data as a raw bytes payload." }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Image Segmentation", "$ref": "#/$defs/ImageSegmentationParameters" } }, "$defs": { "ImageSegmentationParameters": { "title": "ImageSegmentationParameters", - "description": "Additional inference parameters for Image Segmentation", "type": "object", "properties": { "mask_threshold": { diff --git a/packages/tasks/src/tasks/image-to-image/inference.ts b/packages/tasks/src/tasks/image-to-image/inference.ts index 8ba34b5ff..658bbd012 100644 --- a/packages/tasks/src/tasks/image-to-image/inference.ts +++ b/packages/tasks/src/tasks/image-to-image/inference.ts @@ -14,15 +14,13 @@ export interface ImageToImageInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Image To Image */ parameters?: ImageToImageParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Image To Image */ export interface ImageToImageParameters { diff --git a/packages/tasks/src/tasks/image-to-image/spec/input.json b/packages/tasks/src/tasks/image-to-image/spec/input.json index 23695c6b1..5020d84cf 100644 --- a/packages/tasks/src/tasks/image-to-image/spec/input.json +++ b/packages/tasks/src/tasks/image-to-image/spec/input.json @@ -10,14 +10,13 @@ "description": "The input image data as a base64-encoded string. If no `parameters` are provided, you can also provide the image data as a raw bytes payload." }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Image To Image", "$ref": "#/$defs/ImageToImageParameters" } }, "$defs": { "ImageToImageParameters": { "title": "ImageToImageParameters", - "description": "Additional inference parameters for Image To Image", "type": "object", "properties": { "guidance_scale": { diff --git a/packages/tasks/src/tasks/image-to-text/inference.ts b/packages/tasks/src/tasks/image-to-text/inference.ts index 44a95f1f5..fd81b4e62 100644 --- a/packages/tasks/src/tasks/image-to-text/inference.ts +++ b/packages/tasks/src/tasks/image-to-text/inference.ts @@ -13,15 +13,13 @@ export interface ImageToTextInput { */ inputs: unknown; /** - * Additional inference parameters + * Additional inference parameters for Image To Text */ parameters?: ImageToTextParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Image To Text */ export interface ImageToTextParameters { @@ -38,8 +36,6 @@ export interface ImageToTextParameters { /** * Parametrization of the text generation process - * - * Ad-hoc parametrization of the text generation process */ export interface GenerationParameters { /** diff --git a/packages/tasks/src/tasks/image-to-text/spec/input.json b/packages/tasks/src/tasks/image-to-text/spec/input.json index 175868614..7b3fd2756 100644 --- a/packages/tasks/src/tasks/image-to-text/spec/input.json +++ b/packages/tasks/src/tasks/image-to-text/spec/input.json @@ -9,14 +9,13 @@ "description": "The input image data" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Image To Text", "$ref": "#/$defs/ImageToTextParameters" } }, "$defs": { "ImageToTextParameters": { "title": "ImageToTextParameters", - "description": "Additional inference parameters for Image To Text", "type": "object", "properties": { "max_new_tokens": { diff --git a/packages/tasks/src/tasks/object-detection/inference.ts b/packages/tasks/src/tasks/object-detection/inference.ts index d117dcb0b..4bb02bd01 100644 --- a/packages/tasks/src/tasks/object-detection/inference.ts +++ b/packages/tasks/src/tasks/object-detection/inference.ts @@ -13,14 +13,12 @@ export interface ObjectDetectionInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Object Detection */ parameters?: ObjectDetectionParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Object Detection */ export interface ObjectDetectionParameters { diff --git a/packages/tasks/src/tasks/object-detection/spec/input.json b/packages/tasks/src/tasks/object-detection/spec/input.json index d00deefec..948392bf0 100644 --- a/packages/tasks/src/tasks/object-detection/spec/input.json +++ b/packages/tasks/src/tasks/object-detection/spec/input.json @@ -10,14 +10,13 @@ "description": "The input image data as a base64-encoded string. If no `parameters` are provided, you can also provide the image data as a raw bytes payload." }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Object Detection", "$ref": "#/$defs/ObjectDetectionParameters" } }, "$defs": { "ObjectDetectionParameters": { "title": "ObjectDetectionParameters", - "description": "Additional inference parameters for Object Detection", "type": "object", "properties": { "threshold": { diff --git a/packages/tasks/src/tasks/placeholder/spec/input.json b/packages/tasks/src/tasks/placeholder/spec/input.json index d31f4aac6..aab9dd152 100644 --- a/packages/tasks/src/tasks/placeholder/spec/input.json +++ b/packages/tasks/src/tasks/placeholder/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "TODO: describe additional parameters here.", "$ref": "#/$defs/Parameters" } }, "$defs": { "Parameters": { "title": "Parameters", - "description": "TODO: describe additional parameters here.", "type": "object", "properties": { "dummy_parameter_name": { diff --git a/packages/tasks/src/tasks/question-answering/inference.ts b/packages/tasks/src/tasks/question-answering/inference.ts index eaef8dfe3..bd478276b 100644 --- a/packages/tasks/src/tasks/question-answering/inference.ts +++ b/packages/tasks/src/tasks/question-answering/inference.ts @@ -12,7 +12,7 @@ export interface QuestionAnsweringInput { */ inputs: QuestionAnsweringInputData; /** - * Additional inference parameters + * Additional inference parameters for Question Answering */ parameters?: QuestionAnsweringParameters; [property: string]: unknown; @@ -32,8 +32,6 @@ export interface QuestionAnsweringInputData { [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Question Answering */ export interface QuestionAnsweringParameters { diff --git a/packages/tasks/src/tasks/question-answering/spec/input.json b/packages/tasks/src/tasks/question-answering/spec/input.json index 70d5607cf..266b329df 100644 --- a/packages/tasks/src/tasks/question-answering/spec/input.json +++ b/packages/tasks/src/tasks/question-answering/spec/input.json @@ -22,14 +22,13 @@ "required": ["question", "context"] }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Question Answering", "$ref": "#/$defs/QuestionAnsweringParameters" } }, "$defs": { "QuestionAnsweringParameters": { "title": "QuestionAnsweringParameters", - "description": "Additional inference parameters for Question Answering", "type": "object", "properties": { "top_k": { diff --git a/packages/tasks/src/tasks/sentence-similarity/inference.ts b/packages/tasks/src/tasks/sentence-similarity/inference.ts index 646e18b48..277aa4a83 100644 --- a/packages/tasks/src/tasks/sentence-similarity/inference.ts +++ b/packages/tasks/src/tasks/sentence-similarity/inference.ts @@ -12,7 +12,7 @@ export type SentenceSimilarityOutput = number[]; export interface SentenceSimilarityInput { inputs: SentenceSimilarityInputData; /** - * Additional inference parameters + * Additional inference parameters for Sentence Similarity */ parameters?: { [key: string]: unknown }; [property: string]: unknown; diff --git a/packages/tasks/src/tasks/sentence-similarity/spec/input.json b/packages/tasks/src/tasks/sentence-similarity/spec/input.json index ecff3479d..8958f3833 100644 --- a/packages/tasks/src/tasks/sentence-similarity/spec/input.json +++ b/packages/tasks/src/tasks/sentence-similarity/spec/input.json @@ -24,14 +24,13 @@ "required": ["sourceSentence", "sentences"] }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Sentence Similarity", "$ref": "#/$defs/SentenceSimilarityParameters" } }, "$defs": { "SentenceSimilarityParameters": { "title": "SentenceSimilarityParameters", - "description": "Additional inference parameters for Sentence Similarity", "type": "object", "properties": {} } diff --git a/packages/tasks/src/tasks/summarization/inference.ts b/packages/tasks/src/tasks/summarization/inference.ts index a08e25230..ecec9e97e 100644 --- a/packages/tasks/src/tasks/summarization/inference.ts +++ b/packages/tasks/src/tasks/summarization/inference.ts @@ -13,15 +13,13 @@ export interface SummarizationInput { */ inputs: string; /** - * Additional inference parameters. + * Additional inference parameters for summarization. */ parameters?: SummarizationParameters; [property: string]: unknown; } /** - * Additional inference parameters. - * * Additional inference parameters for summarization. */ export interface SummarizationParameters { diff --git a/packages/tasks/src/tasks/summarization/spec/input.json b/packages/tasks/src/tasks/summarization/spec/input.json index d33152857..c2d7aebaf 100644 --- a/packages/tasks/src/tasks/summarization/spec/input.json +++ b/packages/tasks/src/tasks/summarization/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters.", + "description": "Additional inference parameters for summarization.", "$ref": "#/$defs/SummarizationParameters" } }, "$defs": { "SummarizationParameters": { "title": "SummarizationParameters", - "description": "Additional inference parameters for summarization.", "type": "object", "properties": { "clean_up_tokenization_spaces": { diff --git a/packages/tasks/src/tasks/table-question-answering/inference.ts b/packages/tasks/src/tasks/table-question-answering/inference.ts index 7e79fa2c8..65e7afbfc 100644 --- a/packages/tasks/src/tasks/table-question-answering/inference.ts +++ b/packages/tasks/src/tasks/table-question-answering/inference.ts @@ -12,7 +12,7 @@ export interface TableQuestionAnsweringInput { */ inputs: TableQuestionAnsweringInputData; /** - * Additional inference parameters + * Additional inference parameters for Table Question Answering */ parameters?: { [key: string]: unknown; diff --git a/packages/tasks/src/tasks/table-question-answering/spec/input.json b/packages/tasks/src/tasks/table-question-answering/spec/input.json index 3dfdd02a7..ab04107cc 100644 --- a/packages/tasks/src/tasks/table-question-answering/spec/input.json +++ b/packages/tasks/src/tasks/table-question-answering/spec/input.json @@ -28,14 +28,13 @@ "required": ["table", "question"] }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Table Question Answering", "$ref": "#/$defs/TableQuestionAnsweringParameters" } }, "$defs": { "TableQuestionAnsweringParameters": { "title": "TableQuestionAnsweringParameters", - "description": "Additional inference parameters for Table Question Answering", "type": "object", "properties": {} } diff --git a/packages/tasks/src/tasks/text-classification/inference.ts b/packages/tasks/src/tasks/text-classification/inference.ts index 82ab270ea..84d6a80fe 100644 --- a/packages/tasks/src/tasks/text-classification/inference.ts +++ b/packages/tasks/src/tasks/text-classification/inference.ts @@ -12,14 +12,12 @@ export interface TextClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Text Classification */ parameters?: TextClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Text Classification */ export interface TextClassificationParameters { diff --git a/packages/tasks/src/tasks/text-classification/spec/input.json b/packages/tasks/src/tasks/text-classification/spec/input.json index 0b05d59a5..468f865dd 100644 --- a/packages/tasks/src/tasks/text-classification/spec/input.json +++ b/packages/tasks/src/tasks/text-classification/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Text Classification", "$ref": "#/$defs/TextClassificationParameters" } }, "$defs": { "TextClassificationParameters": { "title": "TextClassificationParameters", - "description": "Additional inference parameters for Text Classification", "type": "object", "properties": { "function_to_apply": { diff --git a/packages/tasks/src/tasks/text-to-audio/inference.ts b/packages/tasks/src/tasks/text-to-audio/inference.ts index e1105b82e..f08aa87e1 100644 --- a/packages/tasks/src/tasks/text-to-audio/inference.ts +++ b/packages/tasks/src/tasks/text-to-audio/inference.ts @@ -13,15 +13,13 @@ export interface TextToAudioInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Text To Audio */ parameters?: TextToAudioParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Text To Audio */ export interface TextToAudioParameters { @@ -34,8 +32,6 @@ export interface TextToAudioParameters { /** * Parametrization of the text generation process - * - * Ad-hoc parametrization of the text generation process */ export interface GenerationParameters { /** diff --git a/packages/tasks/src/tasks/text-to-audio/spec/input.json b/packages/tasks/src/tasks/text-to-audio/spec/input.json index 99390c8a9..a836c53d5 100644 --- a/packages/tasks/src/tasks/text-to-audio/spec/input.json +++ b/packages/tasks/src/tasks/text-to-audio/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Text To Audio", "$ref": "#/$defs/TextToAudioParameters" } }, "$defs": { "TextToAudioParameters": { "title": "TextToAudioParameters", - "description": "Additional inference parameters for Text To Audio", "type": "object", "properties": { "generation_parameters": { diff --git a/packages/tasks/src/tasks/text-to-image/inference.ts b/packages/tasks/src/tasks/text-to-image/inference.ts index 8c30d3e9e..ae8a3b6a3 100644 --- a/packages/tasks/src/tasks/text-to-image/inference.ts +++ b/packages/tasks/src/tasks/text-to-image/inference.ts @@ -13,15 +13,13 @@ export interface TextToImageInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Text To Image */ parameters?: TextToImageParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Text To Image */ export interface TextToImageParameters { diff --git a/packages/tasks/src/tasks/text-to-image/spec/input.json b/packages/tasks/src/tasks/text-to-image/spec/input.json index 569f3c33a..bc22f88c2 100644 --- a/packages/tasks/src/tasks/text-to-image/spec/input.json +++ b/packages/tasks/src/tasks/text-to-image/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Text To Image", "$ref": "#/$defs/TextToImageParameters" } }, "$defs": { "TextToImageParameters": { "title": "TextToImageParameters", - "description": "Additional inference parameters for Text To Image", "type": "object", "properties": { "guidance_scale": { diff --git a/packages/tasks/src/tasks/text-to-speech/inference.ts b/packages/tasks/src/tasks/text-to-speech/inference.ts index 765f7526a..230aad902 100644 --- a/packages/tasks/src/tasks/text-to-speech/inference.ts +++ b/packages/tasks/src/tasks/text-to-speech/inference.ts @@ -13,15 +13,13 @@ export interface TextToSpeechInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Text To Speech */ parameters?: TextToSpeechParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Text To Speech */ export interface TextToSpeechParameters { @@ -34,8 +32,6 @@ export interface TextToSpeechParameters { /** * Parametrization of the text generation process - * - * Ad-hoc parametrization of the text generation process */ export interface GenerationParameters { /** diff --git a/packages/tasks/src/tasks/text-to-speech/spec/input.json b/packages/tasks/src/tasks/text-to-speech/spec/input.json index 825d1c30d..a643f2d7c 100644 --- a/packages/tasks/src/tasks/text-to-speech/spec/input.json +++ b/packages/tasks/src/tasks/text-to-speech/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Text To Speech", "$ref": "#/$defs/TextToSpeechParameters" } }, "$defs": { "TextToSpeechParameters": { "title": "TextToSpeechParameters", - "description": "Additional inference parameters for Text To Speech", "type": "object", "properties": { "generation_parameters": { diff --git a/packages/tasks/src/tasks/text2text-generation/inference.ts b/packages/tasks/src/tasks/text2text-generation/inference.ts index 3fb690b70..6bd9dab81 100644 --- a/packages/tasks/src/tasks/text2text-generation/inference.ts +++ b/packages/tasks/src/tasks/text2text-generation/inference.ts @@ -13,15 +13,13 @@ export interface Text2TextGenerationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Text2text Generation */ parameters?: Text2TextGenerationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Text2text Generation */ export interface Text2TextGenerationParameters { diff --git a/packages/tasks/src/tasks/text2text-generation/spec/input.json b/packages/tasks/src/tasks/text2text-generation/spec/input.json index 0310d7478..1b0456738 100644 --- a/packages/tasks/src/tasks/text2text-generation/spec/input.json +++ b/packages/tasks/src/tasks/text2text-generation/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Text2text Generation", "$ref": "#/$defs/Text2textGenerationParameters" } }, "$defs": { "Text2textGenerationParameters": { "title": "Text2textGenerationParameters", - "description": "Additional inference parameters for Text2text Generation", "type": "object", "properties": { "clean_up_tokenization_spaces": { diff --git a/packages/tasks/src/tasks/token-classification/inference.ts b/packages/tasks/src/tasks/token-classification/inference.ts index b218e08de..09f899c6b 100644 --- a/packages/tasks/src/tasks/token-classification/inference.ts +++ b/packages/tasks/src/tasks/token-classification/inference.ts @@ -12,14 +12,12 @@ export interface TokenClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Token Classification */ parameters?: TokenClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Token Classification */ export interface TokenClassificationParameters { diff --git a/packages/tasks/src/tasks/token-classification/spec/input.json b/packages/tasks/src/tasks/token-classification/spec/input.json index 30d6153d2..1176f3dd9 100644 --- a/packages/tasks/src/tasks/token-classification/spec/input.json +++ b/packages/tasks/src/tasks/token-classification/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Token Classification", "$ref": "#/$defs/TokenClassificationParameters" } }, "$defs": { "TokenClassificationParameters": { "title": "TokenClassificationParameters", - "description": "Additional inference parameters for Token Classification", "type": "object", "properties": { "ignore_labels": { diff --git a/packages/tasks/src/tasks/translation/inference.ts b/packages/tasks/src/tasks/translation/inference.ts index a78c7e940..1e517e4c7 100644 --- a/packages/tasks/src/tasks/translation/inference.ts +++ b/packages/tasks/src/tasks/translation/inference.ts @@ -13,15 +13,13 @@ export interface TranslationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Translation */ parameters?: TranslationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Translation */ export interface TranslationParameters { diff --git a/packages/tasks/src/tasks/translation/spec/input.json b/packages/tasks/src/tasks/translation/spec/input.json index 0c2d196cf..8f0a6fc6f 100644 --- a/packages/tasks/src/tasks/translation/spec/input.json +++ b/packages/tasks/src/tasks/translation/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Translation", "$ref": "#/$defs/TranslationParameters" } }, "$defs": { "TranslationParameters": { "title": "TranslationParameters", - "description": "Additional inference parameters for Translation", "type": "object", "properties": { "src_lang": { diff --git a/packages/tasks/src/tasks/video-classification/inference.ts b/packages/tasks/src/tasks/video-classification/inference.ts index e50e0c299..5c937d9c1 100644 --- a/packages/tasks/src/tasks/video-classification/inference.ts +++ b/packages/tasks/src/tasks/video-classification/inference.ts @@ -12,14 +12,12 @@ export interface VideoClassificationInput { */ inputs: unknown; /** - * Additional inference parameters + * Additional inference parameters for Video Classification */ parameters?: VideoClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Video Classification */ export interface VideoClassificationParameters { diff --git a/packages/tasks/src/tasks/video-classification/spec/input.json b/packages/tasks/src/tasks/video-classification/spec/input.json index 8bcef7f75..277950e59 100644 --- a/packages/tasks/src/tasks/video-classification/spec/input.json +++ b/packages/tasks/src/tasks/video-classification/spec/input.json @@ -9,14 +9,13 @@ "description": "The input video data" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Video Classification", "$ref": "#/$defs/VideoClassificationParameters" } }, "$defs": { "VideoClassificationParameters": { "title": "VideoClassificationParameters", - "description": "Additional inference parameters for Video Classification", "type": "object", "properties": { "function_to_apply": { diff --git a/packages/tasks/src/tasks/visual-question-answering/inference.ts b/packages/tasks/src/tasks/visual-question-answering/inference.ts index fbc53f11b..8b774988a 100644 --- a/packages/tasks/src/tasks/visual-question-answering/inference.ts +++ b/packages/tasks/src/tasks/visual-question-answering/inference.ts @@ -12,7 +12,7 @@ export interface VisualQuestionAnsweringInput { */ inputs: VisualQuestionAnsweringInputData; /** - * Additional inference parameters + * Additional inference parameters for Visual Question Answering */ parameters?: VisualQuestionAnsweringParameters; [property: string]: unknown; @@ -32,8 +32,6 @@ export interface VisualQuestionAnsweringInputData { [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Visual Question Answering */ export interface VisualQuestionAnsweringParameters { diff --git a/packages/tasks/src/tasks/visual-question-answering/spec/input.json b/packages/tasks/src/tasks/visual-question-answering/spec/input.json index 9f9dab121..0867bfcf2 100644 --- a/packages/tasks/src/tasks/visual-question-answering/spec/input.json +++ b/packages/tasks/src/tasks/visual-question-answering/spec/input.json @@ -20,14 +20,13 @@ "required": ["question", "image"] }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Visual Question Answering", "$ref": "#/$defs/VisualQuestionAnsweringParameters" } }, "$defs": { "VisualQuestionAnsweringParameters": { "title": "VisualQuestionAnsweringParameters", - "description": "Additional inference parameters for Visual Question Answering", "type": "object", "properties": { "top_k": { diff --git a/packages/tasks/src/tasks/zero-shot-classification/inference.ts b/packages/tasks/src/tasks/zero-shot-classification/inference.ts index 68717f406..aaae36f62 100644 --- a/packages/tasks/src/tasks/zero-shot-classification/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-classification/inference.ts @@ -12,14 +12,12 @@ export interface ZeroShotClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Zero Shot Classification */ parameters: ZeroShotClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Zero Shot Classification */ export interface ZeroShotClassificationParameters { diff --git a/packages/tasks/src/tasks/zero-shot-classification/spec/input.json b/packages/tasks/src/tasks/zero-shot-classification/spec/input.json index fb875bac6..c919eac7e 100644 --- a/packages/tasks/src/tasks/zero-shot-classification/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-classification/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Zero Shot Classification", "$ref": "#/$defs/ZeroShotClassificationParameters" } }, "$defs": { "ZeroShotClassificationParameters": { "title": "ZeroShotClassificationParameters", - "description": "Additional inference parameters for Zero Shot Classification", "type": "object", "properties": { "candidate_labels": { diff --git a/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts b/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts index c1cd4d7a2..594a4b562 100644 --- a/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-image-classification/inference.ts @@ -12,14 +12,12 @@ export interface ZeroShotImageClassificationInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Zero Shot Image Classification */ parameters: ZeroShotImageClassificationParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Zero Shot Image Classification */ export interface ZeroShotImageClassificationParameters { diff --git a/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json b/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json index 85e88d4f2..5795dd287 100644 --- a/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-image-classification/spec/input.json @@ -10,14 +10,13 @@ "description": "The input image data to classify as a base64-encoded string." }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Zero Shot Image Classification", "$ref": "#/$defs/ZeroShotImageClassificationParameters" } }, "$defs": { "ZeroShotImageClassificationParameters": { "title": "ZeroShotImageClassificationParameters", - "description": "Additional inference parameters for Zero Shot Image Classification", "type": "object", "properties": { "candidate_labels": { diff --git a/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts b/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts index dea72430c..860609547 100644 --- a/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts +++ b/packages/tasks/src/tasks/zero-shot-object-detection/inference.ts @@ -12,14 +12,12 @@ export interface ZeroShotObjectDetectionInput { */ inputs: string; /** - * Additional inference parameters + * Additional inference parameters for Zero Shot Object Detection */ parameters: ZeroShotObjectDetectionParameters; [property: string]: unknown; } /** - * Additional inference parameters - * * Additional inference parameters for Zero Shot Object Detection */ export interface ZeroShotObjectDetectionParameters { diff --git a/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json b/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json index 8b57cce72..d3532be05 100644 --- a/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json +++ b/packages/tasks/src/tasks/zero-shot-object-detection/spec/input.json @@ -10,14 +10,13 @@ "type": "string" }, "parameters": { - "description": "Additional inference parameters", + "description": "Additional inference parameters for Zero Shot Object Detection", "$ref": "#/$defs/ZeroShotObjectDetectionParameters" } }, "$defs": { "ZeroShotObjectDetectionParameters": { "title": "ZeroShotObjectDetectionParameters", - "description": "Additional inference parameters for Zero Shot Object Detection", "type": "object", "properties": { "candidate_labels": { From afdfb0b1eb1d25f6929d3155681d9bd6b33c5f5d Mon Sep 17 00:00:00 2001 From: HuggingFaceInfra <148469759+HuggingFaceInfra@users.noreply.github.com> Date: Fri, 22 Nov 2024 04:36:33 -0400 Subject: [PATCH 62/97] [Bot] Update tasks specs (#1030) This PR updates the @huggingface/tasks specs. It has been generated by running: ```sh pnpm run inference-tgi-import pnpm run inference-tei-import pnpm run inference-codegen ``` This PR was automatically created by the [Tasks - Update specs workflow](https://github.com/huggingface/huggingface.js/blob/main/.github/update-specs.yml). Make sure the changes are correct before merging. Co-authored-by: Wauplin <11801849+Wauplin@users.noreply.github.com> --- .../src/tasks/chat-completion/inference.ts | 25 ++++++++++---- .../src/tasks/chat-completion/spec/input.json | 33 ++++++++----------- .../src/tasks/feature-extraction/inference.ts | 2 +- .../tasks/feature-extraction/spec/input.json | 2 +- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/packages/tasks/src/tasks/chat-completion/inference.ts b/packages/tasks/src/tasks/chat-completion/inference.ts index febaffc8f..4c4449a73 100644 --- a/packages/tasks/src/tasks/chat-completion/inference.ts +++ b/packages/tasks/src/tasks/chat-completion/inference.ts @@ -79,7 +79,7 @@ export interface ChatCompletionInput { * We generally recommend altering this or `top_p` but not both. */ temperature?: number; - tool_choice?: ChatCompletionInputTool; + tool_choice?: ChatCompletionInputToolChoice; /** * A prompt to be appended before the tools */ @@ -89,7 +89,7 @@ export interface ChatCompletionInput { * Use this to provide a list of * functions the model may generate JSON inputs for. */ - tools?: ToolElement[]; + tools?: ChatCompletionInputTool[]; /** * An integer between 0 and 5 specifying the number of most likely tokens to return at each * token position, each with @@ -154,10 +154,23 @@ export interface ChatCompletionInputStreamOptions { [property: string]: unknown; } -export type ChatCompletionInputTool = ChatCompletionInputToolType | string; +/** + * + * + */ +export type ChatCompletionInputToolChoice = ChatCompletionInputToolChoiceEnum | ChatCompletionInputToolChoiceObject; + +/** + * Means the model can pick between generating a message or calling one or more tools. + * + * Means the model will not call any tool and instead generates a message. + * + * Means the model must call one or more tools. + */ +export type ChatCompletionInputToolChoiceEnum = "auto" | "none" | "required"; -export interface ChatCompletionInputToolType { - function?: ChatCompletionInputFunctionName; +export interface ChatCompletionInputToolChoiceObject { + function: ChatCompletionInputFunctionName; [property: string]: unknown; } @@ -166,7 +179,7 @@ export interface ChatCompletionInputFunctionName { [property: string]: unknown; } -export interface ToolElement { +export interface ChatCompletionInputTool { function: ChatCompletionInputFunctionDefinition; type: string; [property: string]: unknown; diff --git a/packages/tasks/src/tasks/chat-completion/spec/input.json b/packages/tasks/src/tasks/chat-completion/spec/input.json index 86ca23c82..b34de9953 100644 --- a/packages/tasks/src/tasks/chat-completion/spec/input.json +++ b/packages/tasks/src/tasks/chat-completion/spec/input.json @@ -114,6 +114,7 @@ "$ref": "#/$defs/ChatCompletionInputToolChoice" } ], + "default": "auto", "nullable": true }, "tool_prompt": { @@ -272,23 +273,21 @@ "title": "ChatCompletionInputStreamOptions" }, "ChatCompletionInputToolChoice": { - "allOf": [ - { - "$ref": "#/$defs/ChatCompletionInputToolType" - } - ], - "nullable": true, - "title": "ChatCompletionInputToolChoice" - }, - "ChatCompletionInputToolType": { "oneOf": [ { - "type": "object", - "default": null, - "nullable": true + "type": "string", + "description": "Means the model can pick between generating a message or calling one or more tools.", + "enum": ["auto"] }, { - "type": "string" + "type": "string", + "description": "Means the model will not call any tool and instead generates a message.", + "enum": ["none"] + }, + { + "type": "string", + "description": "Means the model must call one or more tools.", + "enum": ["required"] }, { "type": "object", @@ -298,14 +297,10 @@ "$ref": "#/$defs/ChatCompletionInputFunctionName" } } - }, - { - "type": "object", - "default": null, - "nullable": true } ], - "title": "ChatCompletionInputToolType" + "description": "", + "title": "ChatCompletionInputToolChoice" }, "ChatCompletionInputFunctionName": { "type": "object", diff --git a/packages/tasks/src/tasks/feature-extraction/inference.ts b/packages/tasks/src/tasks/feature-extraction/inference.ts index 96194d7e9..404b10308 100644 --- a/packages/tasks/src/tasks/feature-extraction/inference.ts +++ b/packages/tasks/src/tasks/feature-extraction/inference.ts @@ -23,7 +23,7 @@ export interface FeatureExtractionInput { * The name of the prompt that should be used by for encoding. If not set, no prompt * will be applied. * - * Must be a key in the `Sentence Transformers` configuration `prompts` dictionary. + * Must be a key in the `sentence-transformers` configuration `prompts` dictionary. * * For example if ``prompt_name`` is "query" and the ``prompts`` is {"query": "query: ", * ...}, diff --git a/packages/tasks/src/tasks/feature-extraction/spec/input.json b/packages/tasks/src/tasks/feature-extraction/spec/input.json index 94e8d7a0b..a4fec711a 100644 --- a/packages/tasks/src/tasks/feature-extraction/spec/input.json +++ b/packages/tasks/src/tasks/feature-extraction/spec/input.json @@ -17,7 +17,7 @@ }, "prompt_name": { "type": "string", - "description": "The name of the prompt that should be used by for encoding. If not set, no prompt\nwill be applied.\n\nMust be a key in the `Sentence Transformers` configuration `prompts` dictionary.\n\nFor example if ``prompt_name`` is \"query\" and the ``prompts`` is {\"query\": \"query: \", ...},\nthen the sentence \"What is the capital of France?\" will be encoded as\n\"query: What is the capital of France?\" because the prompt text will be prepended before\nany text to encode.", + "description": "The name of the prompt that should be used by for encoding. If not set, no prompt\nwill be applied.\n\nMust be a key in the `sentence-transformers` configuration `prompts` dictionary.\n\nFor example if ``prompt_name`` is \"query\" and the ``prompts`` is {\"query\": \"query: \", ...},\nthen the sentence \"What is the capital of France?\" will be encoded as\n\"query: What is the capital of France?\" because the prompt text will be prepended before\nany text to encode.", "default": "null", "example": "null", "nullable": true From c63f9aee07f2c6507356c9c01bc2f844f02c891e Mon Sep 17 00:00:00 2001 From: Lucain Date: Mon, 25 Nov 2024 12:35:11 +0100 Subject: [PATCH 63/97] Refacto Inference snippets tests (autogeneration + 1 snippet == 1 file) (#1046) This PR is a refacto of the inference snippet tests. The main goal is to reduce friction when updating the inference snippets logic. In particular: - each generated snippet is saved into a single test file with the correct file extension => should greatly improve reviews. Currently snippets are saved as hardcoded strings in JS files, making them hard to review (no syntax highlighting, weird indentation). - snippets can be updated with a script, reducing the need to manually edit tests (which is quite time-consuming) This PR is quite large given the auto-generated files. The main parts to review are: - `generate-snippets-fixtures.ts` => the script that generates the snippets and test them. - package.json, pnpm lock files, etc. => I'm not entirely sure of what I did there (especially to make `tasks-gen` depend on `tasks`) - `python.spec.ts` / `js.specs.ts` and `curl.specs.ts` have been removed - everything in `packages/tasks-gen/snippets-fixtures/` => the test cases. I've only committed the ones that where previously tested. Thanks to this PR, I fixed a typo in the JS snippets (a missing comma) and curl snippets (consistency between `"` and `'`). cc @mishig25 with whom I quickly discussed this --------- Co-authored-by: Mishig --- packages/tasks-gen/README.md | 67 +++++++ packages/tasks-gen/package.json | 7 +- packages/tasks-gen/pnpm-lock.yaml | 11 +- .../scripts/generate-snippets-fixtures.ts | 178 ++++++++++++++++++ .../0.default.sh | 14 ++ .../0.huggingface.js.js | 16 ++ .../0.huggingface_hub.py | 18 ++ .../conversational-llm-non-stream/1.openai.js | 19 ++ .../conversational-llm-non-stream/1.openai.py | 21 +++ .../conversational-llm-stream/0.default.sh | 14 ++ .../0.huggingface.js.js | 24 +++ .../0.huggingface_hub.py | 20 ++ .../conversational-llm-stream/1.openai.js | 28 +++ .../conversational-llm-stream/1.openai.py | 23 +++ .../0.default.sh | 25 +++ .../0.huggingface.js.js | 27 +++ .../0.huggingface_hub.py | 29 +++ .../conversational-vlm-non-stream/1.openai.js | 30 +++ .../conversational-vlm-non-stream/1.openai.py | 32 ++++ .../conversational-vlm-stream/0.default.sh | 25 +++ .../0.huggingface.js.js | 35 ++++ .../0.huggingface_hub.py | 31 +++ .../conversational-vlm-stream/1.openai.js | 39 ++++ .../conversational-vlm-stream/1.openai.py | 34 ++++ .../text-to-image/0.default.js | 18 ++ .../text-to-image/0.default.sh | 5 + .../text-to-image/0.huggingface_hub.py | 5 + .../text-to-image/1.requests.py | 16 ++ packages/tasks-gen/vitest.config.ts | 8 + packages/tasks/src/snippets/curl.spec.ts | 94 --------- packages/tasks/src/snippets/curl.ts | 8 +- packages/tasks/src/snippets/js.spec.ts | 148 --------------- packages/tasks/src/snippets/js.ts | 10 +- packages/tasks/src/snippets/python.spec.ts | 144 -------------- 34 files changed, 824 insertions(+), 399 deletions(-) create mode 100644 packages/tasks-gen/README.md create mode 100644 packages/tasks-gen/scripts/generate-snippets-fixtures.ts create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.default.sh create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface.js.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface_hub.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.default.sh create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface.js.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface_hub.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.default.sh create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface.js.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface_hub.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.default.sh create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface.js.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface_hub.py create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.js create mode 100644 packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.py create mode 100644 packages/tasks-gen/snippets-fixtures/text-to-image/0.default.js create mode 100644 packages/tasks-gen/snippets-fixtures/text-to-image/0.default.sh create mode 100644 packages/tasks-gen/snippets-fixtures/text-to-image/0.huggingface_hub.py create mode 100644 packages/tasks-gen/snippets-fixtures/text-to-image/1.requests.py create mode 100644 packages/tasks-gen/vitest.config.ts delete mode 100644 packages/tasks/src/snippets/curl.spec.ts delete mode 100644 packages/tasks/src/snippets/js.spec.ts delete mode 100644 packages/tasks/src/snippets/python.spec.ts diff --git a/packages/tasks-gen/README.md b/packages/tasks-gen/README.md new file mode 100644 index 000000000..d78e62450 --- /dev/null +++ b/packages/tasks-gen/README.md @@ -0,0 +1,67 @@ +## @huggingface.js/tasks-gen + +This package is not a published one. It contains scripts that generate or test parts of the `@huggingface.js/tasks` package. + +### generate-snippets-fixtures.ts + +This script generates and tests Inference API snippets. The goal is to have a simple way to review changes in the snippets. +When updating logic in `packages/tasks/src/snippets`, the test snippets must be updated and committed in the same PR. + +To (re-)generate the snippets, run: + +``` +pnpm generate-snippets-fixtures +``` + +If some logic has been updated, you should see the result with a +``` +git diff +# the diff has to be committed if correct +``` + +To test the snippets, run: + +``` +pnpm test +``` + +Finally if you want to add a test case, you must add an entry in `TEST_CASES` array in `generate-snippets-fixtures.ts`. + +### inference-codegen.ts + +Generates JS and Python dataclasses based on the Inference Specs (jsonschema files). + +This script is run by a cron job once a day and helps getting `@huggingface.js/tasks` and `huggingface_hub` up to date. + +To update the specs manually, run: + +``` +pnpm inference-codegen +``` + +### inference-tei-import.ts + +Fetches TEI specs and generates JSON schema for input and output of text-embeddings (also called feature-extraction). +See https://huggingface.github.io/text-embeddings-inference/ for more details. + +This script is run by a cron job once a day and helps getting `@huggingface.js/tasks` up to date with TEI updates. + +To update the specs manually, run: + +``` +pnpm inference-tei-import +``` + +### inference-tgi-import.ts + +Fetches TGI specs and generates JSON schema for input, output and stream_output of text-generation and chat-completion tasks. +See https://huggingface.github.io/text-generation-inference/ for more details. + +This script is run by a cron job once a day and helps getting `@huggingface.js/tasks` up to date with TGI updates. + +To update the specs manually, run: + +``` +pnpm inference-tgi-import +``` + diff --git a/packages/tasks-gen/package.json b/packages/tasks-gen/package.json index 2d74c82a0..23ad43cfc 100644 --- a/packages/tasks-gen/package.json +++ b/packages/tasks-gen/package.json @@ -11,9 +11,11 @@ "format": "prettier --write .", "format:check": "prettier --check .", "check": "tsc", + "generate-snippets-fixtures": "tsx scripts/generate-snippets-fixtures.ts", "inference-codegen": "tsx scripts/inference-codegen.ts && prettier --write ../tasks/src/tasks/*/inference.ts", "inference-tgi-import": "tsx scripts/inference-tgi-import.ts && prettier --write ../tasks/src/tasks/text-generation/spec/*.json && prettier --write ../tasks/src/tasks/chat-completion/spec/*.json", - "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write ../tasks/src/tasks/feature-extraction/spec/*.json" + "inference-tei-import": "tsx scripts/inference-tei-import.ts && prettier --write ../tasks/src/tasks/feature-extraction/spec/*.json", + "test": "vitest run" }, "type": "module", "author": "Hugging Face", @@ -22,5 +24,8 @@ "@types/node": "^20.11.5", "quicktype-core": "https://github.com/huggingface/quicktype/raw/pack-18.0.17/packages/quicktype-core/quicktype-core-18.0.17.tgz", "type-fest": "^3.13.1" + }, + "dependencies": { + "@huggingface/tasks": "workspace:^" } } diff --git a/packages/tasks-gen/pnpm-lock.yaml b/packages/tasks-gen/pnpm-lock.yaml index f8534970c..f754b702e 100644 --- a/packages/tasks-gen/pnpm-lock.yaml +++ b/packages/tasks-gen/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + '@huggingface/tasks': + specifier: workspace:^ + version: link:../tasks + devDependencies: '@types/node': specifier: ^20.11.5 @@ -192,8 +197,8 @@ packages: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true - /yaml@2.6.0: - resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + /yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} engines: {node: '>= 14'} hasBin: true dev: true @@ -217,7 +222,7 @@ packages: unicode-properties: 1.4.1 urijs: 1.19.11 wordwrap: 1.0.0 - yaml: 2.6.0 + yaml: 2.6.1 transitivePeerDependencies: - encoding dev: true diff --git a/packages/tasks-gen/scripts/generate-snippets-fixtures.ts b/packages/tasks-gen/scripts/generate-snippets-fixtures.ts new file mode 100644 index 000000000..1107d78a5 --- /dev/null +++ b/packages/tasks-gen/scripts/generate-snippets-fixtures.ts @@ -0,0 +1,178 @@ +/* + * Generates Inference API snippets using @huggingface/tasks snippets. + * + * If used in test mode ("pnpm test"), it compares the generated snippets with the expected ones. + * If used in generation mode ("pnpm generate-snippets-fixtures"), it generates the expected snippets. + * + * Expected snippets are saved under ./snippets-fixtures and are meant to be versioned on GitHub. + * Each snippet is saved in a separate file placed under "./{test-name}/{index}.{client}.{language}": + * - test-name: the name of the test (e.g. "text-to-image", "conversational-llm", etc.) + * - index: the order of the snippet in the array of snippets (0 if not an array) + * - client: the client name (e.g. "requests", "huggingface_hub", "openai", etc.). Default to "default" if client is not specified. + * - language: the language of the snippet (e.g. "sh", "js", "py", etc.) + * + * Example: + * ./packages/tasks-gen/snippets-fixtures/text-to-image/0.huggingface_hub.py + */ + +import { existsSync as pathExists } from "node:fs"; +import * as fs from "node:fs/promises"; +import * as path from "node:path/posix"; + +import type { InferenceSnippet } from "@huggingface/tasks"; +import { snippets } from "@huggingface/tasks"; + +type LANGUAGE = "sh" | "js" | "py"; + +const TEST_CASES: { + testName: string; + model: snippets.ModelDataMinimal; + languages: LANGUAGE[]; + opts?: Record; +}[] = [ + { + testName: "conversational-llm-non-stream", + model: { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }, + languages: ["sh", "js", "py"], + opts: { streaming: false }, + }, + { + testName: "conversational-llm-stream", + model: { + id: "meta-llama/Llama-3.1-8B-Instruct", + pipeline_tag: "text-generation", + tags: ["conversational"], + inference: "", + }, + languages: ["sh", "js", "py"], + opts: { streaming: true }, + }, + { + testName: "conversational-vlm-non-stream", + model: { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }, + languages: ["sh", "js", "py"], + opts: { streaming: false }, + }, + { + testName: "conversational-vlm-stream", + model: { + id: "meta-llama/Llama-3.2-11B-Vision-Instruct", + pipeline_tag: "image-text-to-text", + tags: ["conversational"], + inference: "", + }, + languages: ["sh", "js", "py"], + opts: { streaming: true }, + }, + { + testName: "text-to-image", + model: { + id: "black-forest-labs/FLUX.1-schnell", + pipeline_tag: "text-to-image", + tags: [], + inference: "", + }, + languages: ["sh", "js", "py"], + }, +] as const; + +const GET_SNIPPET_FN = { + sh: snippets.curl.getCurlInferenceSnippet, + js: snippets.js.getJsInferenceSnippet, + py: snippets.python.getPythonInferenceSnippet, +} as const; + +const rootDirFinder = (): string => { + let currentPath = path.normalize(import.meta.url).replace("file:", ""); + + while (currentPath !== "/") { + if (pathExists(path.join(currentPath, "package.json"))) { + return currentPath; + } + + currentPath = path.normalize(path.join(currentPath, "..")); + } + + return "/"; +}; + +function getFixtureFolder(testName: string): string { + return path.join(rootDirFinder(), "snippets-fixtures", testName); +} + +function generateInferenceSnippet( + model: snippets.ModelDataMinimal, + language: LANGUAGE, + opts?: Record +): InferenceSnippet[] { + const generatedSnippets = GET_SNIPPET_FN[language](model, "api_token", opts); + return Array.isArray(generatedSnippets) ? generatedSnippets : [generatedSnippets]; +} + +async function getExpectedInferenceSnippet(testName: string, language: LANGUAGE): Promise { + const fixtureFolder = getFixtureFolder(testName); + const files = await fs.readdir(fixtureFolder); + + const expectedSnippets: InferenceSnippet[] = []; + for (const file of files.filter((file) => file.endsWith("." + language)).sort()) { + const client = path.basename(file).split(".").slice(1, -1).join("."); // e.g. '0.huggingface.js.js' => "huggingface.js" + const content = await fs.readFile(path.join(fixtureFolder, file), { encoding: "utf-8" }); + expectedSnippets.push(client === "default" ? { content } : { client, content }); + } + return expectedSnippets; +} + +async function saveExpectedInferenceSnippet(testName: string, language: LANGUAGE, snippets: InferenceSnippet[]) { + const fixtureFolder = getFixtureFolder(testName); + await fs.mkdir(fixtureFolder, { recursive: true }); + + for (const [index, snippet] of snippets.entries()) { + const file = path.join(fixtureFolder, `${index}.${snippet.client ?? "default"}.${language}`); + await fs.writeFile(file, snippet.content); + } +} + +if (import.meta.vitest) { + // Run test if in test mode + const { describe, expect, it } = import.meta.vitest; + + describe("inference API snippets", () => { + TEST_CASES.forEach(({ testName, model, languages, opts }) => { + describe(testName, () => { + languages.forEach((language) => { + it(language, async () => { + const generatedSnippets = generateInferenceSnippet(model, language, opts); + const expectedSnippets = await getExpectedInferenceSnippet(testName, language); + expect(generatedSnippets).toEqual(expectedSnippets); + }); + }); + }); + }); + }); +} else { + // Otherwise, generate the fixtures + console.log("✨ Re-generating snippets"); + console.debug(" 🚜 Removing existing fixtures..."); + await fs.rm(path.join(rootDirFinder(), "snippets-fixtures"), { recursive: true, force: true }); + + console.debug(" 🏭 Generating new fixtures..."); + TEST_CASES.forEach(({ testName, model, languages, opts }) => { + console.debug(` ${testName} (${languages.join(", ")})`); + languages.forEach(async (language) => { + const generatedSnippets = generateInferenceSnippet(model, language, opts); + await saveExpectedInferenceSnippet(testName, language, generatedSnippets); + }); + }); + console.log("✅ All done!"); + console.log("👉 Please check the generated fixtures before committing them."); +} diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.default.sh b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.default.sh new file mode 100644 index 000000000..6f9cf0d70 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.default.sh @@ -0,0 +1,14 @@ +curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \ +-H 'Authorization: Bearer api_token' \ +-H 'Content-Type: application/json' \ +--data '{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "messages": [ + { + "role": "user", + "content": "What is the capital of France?" + } + ], + "max_tokens": 500, + "stream": false +}' \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface.js.js b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface.js.js new file mode 100644 index 000000000..c9243e179 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface.js.js @@ -0,0 +1,16 @@ +import { HfInference } from "@huggingface/inference"; + +const client = new HfInference("api_token"); + +const chatCompletion = await client.chatCompletion({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + +console.log(chatCompletion.choices[0].message); \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface_hub.py b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface_hub.py new file mode 100644 index 000000000..e60e63114 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/0.huggingface_hub.py @@ -0,0 +1,18 @@ +from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +completion = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500 +) + +print(completion.choices[0].message) \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.js b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.js new file mode 100644 index 000000000..ddccf8d50 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.js @@ -0,0 +1,19 @@ +import { OpenAI } from "openai"; + +const client = new OpenAI({ + baseURL: "https://api-inference.huggingface.co/v1/", + apiKey: "api_token" +}); + +const chatCompletion = await client.chat.completions.create({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + +console.log(chatCompletion.choices[0].message); \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.py b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.py new file mode 100644 index 000000000..e6f4b1b47 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-non-stream/1.openai.py @@ -0,0 +1,21 @@ +from openai import OpenAI + +client = OpenAI( + base_url="https://api-inference.huggingface.co/v1/", + api_key="api_token" +) + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +completion = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500 +) + +print(completion.choices[0].message) \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.default.sh b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.default.sh new file mode 100644 index 000000000..42c9e2603 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.default.sh @@ -0,0 +1,14 @@ +curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \ +-H 'Authorization: Bearer api_token' \ +-H 'Content-Type: application/json' \ +--data '{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "messages": [ + { + "role": "user", + "content": "What is the capital of France?" + } + ], + "max_tokens": 500, + "stream": true +}' \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface.js.js b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface.js.js new file mode 100644 index 000000000..581e0a3e8 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface.js.js @@ -0,0 +1,24 @@ +import { HfInference } from "@huggingface/inference"; + +const client = new HfInference("api_token"); + +let out = ""; + +const stream = client.chatCompletionStream({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500 +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +} \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface_hub.py b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface_hub.py new file mode 100644 index 000000000..38a5efcd6 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/0.huggingface_hub.py @@ -0,0 +1,20 @@ +from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="") \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.js b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.js new file mode 100644 index 000000000..ccb3cb15b --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.js @@ -0,0 +1,28 @@ +import { OpenAI } from "openai"; + +const client = new OpenAI({ + baseURL: "https://api-inference.huggingface.co/v1/", + apiKey: "api_token" +}); + +let out = ""; + +const stream = await client.chat.completions.create({ + model: "meta-llama/Llama-3.1-8B-Instruct", + messages: [ + { + role: "user", + content: "What is the capital of France?" + } + ], + max_tokens: 500, + stream: true, +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +} \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.py b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.py new file mode 100644 index 000000000..909a6e9e4 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-llm-stream/1.openai.py @@ -0,0 +1,23 @@ +from openai import OpenAI + +client = OpenAI( + base_url="https://api-inference.huggingface.co/v1/", + api_key="api_token" +) + +messages = [ + { + "role": "user", + "content": "What is the capital of France?" + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.1-8B-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="") \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.default.sh b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.default.sh new file mode 100644 index 000000000..11df13c0b --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.default.sh @@ -0,0 +1,25 @@ +curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions' \ +-H 'Authorization: Bearer api_token' \ +-H 'Content-Type: application/json' \ +--data '{ + "model": "meta-llama/Llama-3.2-11B-Vision-Instruct", + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + "max_tokens": 500, + "stream": false +}' \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface.js.js b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface.js.js new file mode 100644 index 000000000..b7e54db67 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface.js.js @@ -0,0 +1,27 @@ +import { HfInference } from "@huggingface/inference"; + +const client = new HfInference("api_token"); + +const chatCompletion = await client.chatCompletion({ + model: "meta-llama/Llama-3.2-11B-Vision-Instruct", + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence." + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + max_tokens: 500 +}); + +console.log(chatCompletion.choices[0].message); \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface_hub.py b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface_hub.py new file mode 100644 index 000000000..82c238997 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/0.huggingface_hub.py @@ -0,0 +1,29 @@ +from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } +] + +completion = client.chat.completions.create( + model="meta-llama/Llama-3.2-11B-Vision-Instruct", + messages=messages, + max_tokens=500 +) + +print(completion.choices[0].message) \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.js b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.js new file mode 100644 index 000000000..6badefd52 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.js @@ -0,0 +1,30 @@ +import { OpenAI } from "openai"; + +const client = new OpenAI({ + baseURL: "https://api-inference.huggingface.co/v1/", + apiKey: "api_token" +}); + +const chatCompletion = await client.chat.completions.create({ + model: "meta-llama/Llama-3.2-11B-Vision-Instruct", + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence." + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + max_tokens: 500 +}); + +console.log(chatCompletion.choices[0].message); \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.py b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.py new file mode 100644 index 000000000..7a68e8b2c --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-non-stream/1.openai.py @@ -0,0 +1,32 @@ +from openai import OpenAI + +client = OpenAI( + base_url="https://api-inference.huggingface.co/v1/", + api_key="api_token" +) + +messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } +] + +completion = client.chat.completions.create( + model="meta-llama/Llama-3.2-11B-Vision-Instruct", + messages=messages, + max_tokens=500 +) + +print(completion.choices[0].message) \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.default.sh b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.default.sh new file mode 100644 index 000000000..5b60847e1 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.default.sh @@ -0,0 +1,25 @@ +curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions' \ +-H 'Authorization: Bearer api_token' \ +-H 'Content-Type: application/json' \ +--data '{ + "model": "meta-llama/Llama-3.2-11B-Vision-Instruct", + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + "max_tokens": 500, + "stream": true +}' \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface.js.js b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface.js.js new file mode 100644 index 000000000..e91f14d81 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface.js.js @@ -0,0 +1,35 @@ +import { HfInference } from "@huggingface/inference"; + +const client = new HfInference("api_token"); + +let out = ""; + +const stream = client.chatCompletionStream({ + model: "meta-llama/Llama-3.2-11B-Vision-Instruct", + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence." + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + max_tokens: 500 +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +} \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface_hub.py b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface_hub.py new file mode 100644 index 000000000..9eaf7a167 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/0.huggingface_hub.py @@ -0,0 +1,31 @@ +from huggingface_hub import InferenceClient + +client = InferenceClient(api_key="api_token") + +messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.2-11B-Vision-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="") \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.js b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.js new file mode 100644 index 000000000..59447faa0 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.js @@ -0,0 +1,39 @@ +import { OpenAI } from "openai"; + +const client = new OpenAI({ + baseURL: "https://api-inference.huggingface.co/v1/", + apiKey: "api_token" +}); + +let out = ""; + +const stream = await client.chat.completions.create({ + model: "meta-llama/Llama-3.2-11B-Vision-Instruct", + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: "Describe this image in one sentence." + }, + { + type: "image_url", + image_url: { + url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } + ], + max_tokens: 500, + stream: true, +}); + +for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + const newContent = chunk.choices[0].delta.content; + out += newContent; + console.log(newContent); + } +} \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.py b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.py new file mode 100644 index 000000000..a3fe75bcf --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/conversational-vlm-stream/1.openai.py @@ -0,0 +1,34 @@ +from openai import OpenAI + +client = OpenAI( + base_url="https://api-inference.huggingface.co/v1/", + api_key="api_token" +) + +messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Describe this image in one sentence." + }, + { + "type": "image_url", + "image_url": { + "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" + } + } + ] + } +] + +stream = client.chat.completions.create( + model="meta-llama/Llama-3.2-11B-Vision-Instruct", + messages=messages, + max_tokens=500, + stream=True +) + +for chunk in stream: + print(chunk.choices[0].delta.content, end="") \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.js b/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.js new file mode 100644 index 000000000..b5ec56c29 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.js @@ -0,0 +1,18 @@ +async function query(data) { + const response = await fetch( + "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell", + { + headers: { + Authorization: "Bearer api_token", + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify(data), + } + ); + const result = await response.blob(); + return result; +} +query({"inputs": "Astronaut riding a horse"}).then((response) => { + // Use image +}); \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.sh b/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.sh new file mode 100644 index 000000000..73f3c2d54 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/text-to-image/0.default.sh @@ -0,0 +1,5 @@ +curl https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell \ + -X POST \ + -d '{"inputs": "Astronaut riding a horse"}' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer api_token' \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/text-to-image/0.huggingface_hub.py b/packages/tasks-gen/snippets-fixtures/text-to-image/0.huggingface_hub.py new file mode 100644 index 000000000..a0914bc5e --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/text-to-image/0.huggingface_hub.py @@ -0,0 +1,5 @@ +from huggingface_hub import InferenceClient +client = InferenceClient("black-forest-labs/FLUX.1-schnell", token="api_token") + +# output is a PIL.Image object +image = client.text_to_image("Astronaut riding a horse") \ No newline at end of file diff --git a/packages/tasks-gen/snippets-fixtures/text-to-image/1.requests.py b/packages/tasks-gen/snippets-fixtures/text-to-image/1.requests.py new file mode 100644 index 000000000..e71ec1936 --- /dev/null +++ b/packages/tasks-gen/snippets-fixtures/text-to-image/1.requests.py @@ -0,0 +1,16 @@ +import requests + +API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell" +headers = {"Authorization": "Bearer api_token"} + +def query(payload): + response = requests.post(API_URL, headers=headers, json=payload) + return response.content +image_bytes = query({ + "inputs": "Astronaut riding a horse", +}) + +# You can access the image with PIL.Image for example +import io +from PIL import Image +image = Image.open(io.BytesIO(image_bytes)) \ No newline at end of file diff --git a/packages/tasks-gen/vitest.config.ts b/packages/tasks-gen/vitest.config.ts new file mode 100644 index 000000000..3cd4d43fb --- /dev/null +++ b/packages/tasks-gen/vitest.config.ts @@ -0,0 +1,8 @@ +// vitest.config.ts +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + includeSource: ["scripts/generate-snippets-fixtures.ts"], + }, +}); diff --git a/packages/tasks/src/snippets/curl.spec.ts b/packages/tasks/src/snippets/curl.spec.ts deleted file mode 100644 index 8c025ca19..000000000 --- a/packages/tasks/src/snippets/curl.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { ModelDataMinimal } from "./types.js"; -import { describe, expect, it } from "vitest"; -import { getCurlInferenceSnippet } from "./curl.js"; - -describe("inference API snippets", () => { - it("conversational llm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getCurlInferenceSnippet(model, "api_token"); - - expect(snippet.content) - .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \\ --H "Authorization: Bearer api_token" \\ --H 'Content-Type: application/json' \\ ---data '{ - "model": "meta-llama/Llama-3.1-8B-Instruct", - "messages": [ - { - "role": "user", - "content": "What is the capital of France?" - } - ], - "max_tokens": 500, - "stream": true -}'`); - }); - - it("conversational llm non-streaming", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getCurlInferenceSnippet(model, "api_token", { streaming: false }); - - expect(snippet.content) - .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.1-8B-Instruct/v1/chat/completions' \\ --H "Authorization: Bearer api_token" \\ --H 'Content-Type: application/json' \\ ---data '{ - "model": "meta-llama/Llama-3.1-8B-Instruct", - "messages": [ - { - "role": "user", - "content": "What is the capital of France?" - } - ], - "max_tokens": 500, - "stream": false -}'`); - }); - - it("conversational vlm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.2-11B-Vision-Instruct", - pipeline_tag: "image-text-to-text", - tags: ["conversational"], - inference: "", - }; - const snippet = getCurlInferenceSnippet(model, "api_token"); - - expect(snippet.content) - .toEqual(`curl 'https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions' \\ --H "Authorization: Bearer api_token" \\ --H 'Content-Type: application/json' \\ ---data '{ - "model": "meta-llama/Llama-3.2-11B-Vision-Instruct", - "messages": [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Describe this image in one sentence." - }, - { - "type": "image_url", - "image_url": { - "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" - } - } - ] - } - ], - "max_tokens": 500, - "stream": true -}'`); - }); -}); diff --git a/packages/tasks/src/snippets/curl.ts b/packages/tasks/src/snippets/curl.ts index 8b04d55d1..f3ba735f3 100644 --- a/packages/tasks/src/snippets/curl.ts +++ b/packages/tasks/src/snippets/curl.ts @@ -9,7 +9,7 @@ export const snippetBasic = (model: ModelDataMinimal, accessToken: string): Infe -X POST \\ -d '{"inputs": ${getModelInputSnippet(model, true)}}' \\ -H 'Content-Type: application/json' \\ - -H "Authorization: Bearer ${accessToken || `{API_TOKEN}`}"`, + -H 'Authorization: Bearer ${accessToken || `{API_TOKEN}`}'`, }); export const snippetTextGeneration = ( @@ -36,7 +36,7 @@ export const snippetTextGeneration = ( }; return { content: `curl 'https://api-inference.huggingface.co/models/${model.id}/v1/chat/completions' \\ --H "Authorization: Bearer ${accessToken || `{API_TOKEN}`}" \\ +-H 'Authorization: Bearer ${accessToken || `{API_TOKEN}`}' \\ -H 'Content-Type: application/json' \\ --data '{ "model": "${model.id}", @@ -63,14 +63,14 @@ export const snippetZeroShotClassification = (model: ModelDataMinimal, accessTok -X POST \\ -d '{"inputs": ${getModelInputSnippet(model, true)}, "parameters": {"candidate_labels": ["refund", "legal", "faq"]}}' \\ -H 'Content-Type: application/json' \\ - -H "Authorization: Bearer ${accessToken || `{API_TOKEN}`}"`, + -H 'Authorization: Bearer ${accessToken || `{API_TOKEN}`}'`, }); export const snippetFile = (model: ModelDataMinimal, accessToken: string): InferenceSnippet => ({ content: `curl https://api-inference.huggingface.co/models/${model.id} \\ -X POST \\ --data-binary '@${getModelInputSnippet(model, true, true)}' \\ - -H "Authorization: Bearer ${accessToken || `{API_TOKEN}`}"`, + -H 'Authorization: Bearer ${accessToken || `{API_TOKEN}`}'`, }); export const curlSnippets: Partial< diff --git a/packages/tasks/src/snippets/js.spec.ts b/packages/tasks/src/snippets/js.spec.ts deleted file mode 100644 index 50be868aa..000000000 --- a/packages/tasks/src/snippets/js.spec.ts +++ /dev/null @@ -1,148 +0,0 @@ -import type { InferenceSnippet, ModelDataMinimal } from "./types.js"; -import { describe, expect, it } from "vitest"; -import { getJsInferenceSnippet } from "./js.js"; - -describe("inference API snippets", () => { - it("conversational llm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; - -const client = new HfInference("api_token"); - -let out = ""; - -const stream = client.chatCompletionStream({ - model: "meta-llama/Llama-3.1-8B-Instruct", - messages: [ - { - role: "user", - content: "What is the capital of France?" - } - ], - max_tokens: 500 -}); - -for await (const chunk of stream) { - if (chunk.choices && chunk.choices.length > 0) { - const newContent = chunk.choices[0].delta.content; - out += newContent; - console.log(newContent); - } -}`); - }); - - it("conversational llm non-streaming", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getJsInferenceSnippet(model, "api_token", { streaming: false }) as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; - -const client = new HfInference("api_token"); - -const chatCompletion = await client.chatCompletion({ - model: "meta-llama/Llama-3.1-8B-Instruct", - messages: [ - { - role: "user", - content: "What is the capital of France?" - } - ], - max_tokens: 500 -}); - -console.log(chatCompletion.choices[0].message);`); - }); - - it("conversational vlm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.2-11B-Vision-Instruct", - pipeline_tag: "image-text-to-text", - tags: ["conversational"], - inference: "", - }; - const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; - -const client = new HfInference("api_token"); - -let out = ""; - -const stream = client.chatCompletionStream({ - model: "meta-llama/Llama-3.2-11B-Vision-Instruct", - messages: [ - { - role: "user", - content: [ - { - type: "text", - text: "Describe this image in one sentence." - }, - { - type: "image_url", - image_url: { - url: "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" - } - } - ] - } - ], - max_tokens: 500 -}); - -for await (const chunk of stream) { - if (chunk.choices && chunk.choices.length > 0) { - const newContent = chunk.choices[0].delta.content; - out += newContent; - console.log(newContent); - } -}`); - }); - - it("conversational llm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getJsInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`import { HfInference } from "@huggingface/inference"; - -const client = new HfInference("api_token"); - -let out = ""; - -const stream = client.chatCompletionStream({ - model: "meta-llama/Llama-3.1-8B-Instruct", - messages: [ - { - role: "user", - content: "What is the capital of France?" - } - ], - max_tokens: 500 -}); - -for await (const chunk of stream) { - if (chunk.choices && chunk.choices.length > 0) { - const newContent = chunk.choices[0].delta.content; - out += newContent; - console.log(newContent); - } -}`); - }); -}); diff --git a/packages/tasks/src/snippets/js.ts b/packages/tasks/src/snippets/js.ts index e1124fa1e..970752582 100644 --- a/packages/tasks/src/snippets/js.ts +++ b/packages/tasks/src/snippets/js.ts @@ -10,7 +10,7 @@ export const snippetBasic = (model: ModelDataMinimal, accessToken: string): Infe "https://api-inference.huggingface.co/models/${model.id}", { headers: { - Authorization: "Bearer ${accessToken || `{API_TOKEN}`}" + Authorization: "Bearer ${accessToken || `{API_TOKEN}`}", "Content-Type": "application/json", }, method: "POST", @@ -151,7 +151,7 @@ export const snippetZeroShotClassification = (model: ModelDataMinimal, accessTok "https://api-inference.huggingface.co/models/${model.id}", { headers: { - Authorization: "Bearer ${accessToken || `{API_TOKEN}`}" + Authorization: "Bearer ${accessToken || `{API_TOKEN}`}", "Content-Type": "application/json", }, method: "POST", @@ -175,7 +175,7 @@ export const snippetTextToImage = (model: ModelDataMinimal, accessToken: string) "https://api-inference.huggingface.co/models/${model.id}", { headers: { - Authorization: "Bearer ${accessToken || `{API_TOKEN}`}" + Authorization: "Bearer ${accessToken || `{API_TOKEN}`}", "Content-Type": "application/json", }, method: "POST", @@ -196,7 +196,7 @@ export const snippetTextToAudio = (model: ModelDataMinimal, accessToken: string) "https://api-inference.huggingface.co/models/${model.id}", { headers: { - Authorization: "Bearer ${accessToken || `{API_TOKEN}`}" + Authorization: "Bearer ${accessToken || `{API_TOKEN}`}", "Content-Type": "application/json", }, method: "POST", @@ -238,7 +238,7 @@ export const snippetFile = (model: ModelDataMinimal, accessToken: string): Infer "https://api-inference.huggingface.co/models/${model.id}", { headers: { - Authorization: "Bearer ${accessToken || `{API_TOKEN}`}" + Authorization: "Bearer ${accessToken || `{API_TOKEN}`}", "Content-Type": "application/json", }, method: "POST", diff --git a/packages/tasks/src/snippets/python.spec.ts b/packages/tasks/src/snippets/python.spec.ts deleted file mode 100644 index 01ab4fcf4..000000000 --- a/packages/tasks/src/snippets/python.spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -import type { InferenceSnippet, ModelDataMinimal } from "./types.js"; -import { describe, expect, it } from "vitest"; -import { getPythonInferenceSnippet } from "./python.js"; - -describe("inference API snippets", () => { - it("conversational llm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient - -client = InferenceClient(api_key="api_token") - -messages = [ - { - "role": "user", - "content": "What is the capital of France?" - } -] - -stream = client.chat.completions.create( - model="meta-llama/Llama-3.1-8B-Instruct", - messages=messages, - max_tokens=500, - stream=True -) - -for chunk in stream: - print(chunk.choices[0].delta.content, end="")`); - }); - - it("conversational llm non-streaming", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.1-8B-Instruct", - pipeline_tag: "text-generation", - tags: ["conversational"], - inference: "", - }; - const snippet = getPythonInferenceSnippet(model, "api_token", { streaming: false }) as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient - -client = InferenceClient(api_key="api_token") - -messages = [ - { - "role": "user", - "content": "What is the capital of France?" - } -] - -completion = client.chat.completions.create( - model="meta-llama/Llama-3.1-8B-Instruct", - messages=messages, - max_tokens=500 -) - -print(completion.choices[0].message)`); - }); - - it("conversational vlm", async () => { - const model: ModelDataMinimal = { - id: "meta-llama/Llama-3.2-11B-Vision-Instruct", - pipeline_tag: "image-text-to-text", - tags: ["conversational"], - inference: "", - }; - const snippet = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippet[0].content).toEqual(`from huggingface_hub import InferenceClient - -client = InferenceClient(api_key="api_token") - -messages = [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Describe this image in one sentence." - }, - { - "type": "image_url", - "image_url": { - "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" - } - } - ] - } -] - -stream = client.chat.completions.create( - model="meta-llama/Llama-3.2-11B-Vision-Instruct", - messages=messages, - max_tokens=500, - stream=True -) - -for chunk in stream: - print(chunk.choices[0].delta.content, end="")`); - }); - - it("text-to-image", async () => { - const model: ModelDataMinimal = { - id: "black-forest-labs/FLUX.1-schnell", - pipeline_tag: "text-to-image", - tags: [], - inference: "", - }; - const snippets = getPythonInferenceSnippet(model, "api_token") as InferenceSnippet[]; - - expect(snippets.length).toEqual(2); - - expect(snippets[0].client).toEqual("huggingface_hub"); - expect(snippets[0].content).toEqual(`from huggingface_hub import InferenceClient -client = InferenceClient("black-forest-labs/FLUX.1-schnell", token="api_token") - -# output is a PIL.Image object -image = client.text_to_image("Astronaut riding a horse")`); - - expect(snippets[1].client).toEqual("requests"); - expect(snippets[1].content).toEqual(`import requests - -API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell" -headers = {"Authorization": "Bearer api_token"} - -def query(payload): - response = requests.post(API_URL, headers=headers, json=payload) - return response.content -image_bytes = query({ - "inputs": "Astronaut riding a horse", -}) - -# You can access the image with PIL.Image for example -import io -from PIL import Image -image = Image.open(io.BytesIO(image_bytes))`); - }); -}); From e660c358073eb5e4232e33badb729c3f35eb03a4 Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 25 Nov 2024 22:42:12 +0000 Subject: [PATCH 64/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index a02c29488..7bc2fcda2 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.5", + "version": "0.13.6", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From aa8ef2e84f3aee1135e2fad9ff35b4018bd53cc3 Mon Sep 17 00:00:00 2001 From: Neal DeBuhr Date: Tue, 26 Nov 2024 13:20:02 -0500 Subject: [PATCH 65/97] Add CXR Foundation and Derm Foundation model libraries (Google Health AI) (#1049) For two Google Health AI models, a primary usage pattern (with supporting documentation and notebooks) is downloading only the precomputed .npz embeddings. As such, I'm submitting for two new model libraries which are essentially an extension of the TF Keras model library, but they cleanly handle the non-`saved_model.pb` usage pattern in the `countDownload` override. This PR was designed to conform with https://huggingface.co/docs/hub/en/models-download-stats and https://huggingface.co/docs/hub/en/models-adding-libraries#register-your-library. Public models https://huggingface.co/google/cxr-foundation and https://huggingface.co/google/derm-foundation will be switched over once this PR is merged. --------- Co-authored-by: vb --- packages/tasks/src/model-libraries.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 9118a1eda..d8d31a2d4 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -150,6 +150,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: false, countDownloads: `path:"adapter_config.json"`, }, + "cxr-foundation": { + prettyLabel: "CXR Foundation", + repoName: "cxr-foundation", + repoUrl: "https://github.com/google-health/cxr-foundation", + filter: false, + countDownloads: `path:"precomputed_embeddings/embeddings.npz" OR path:"pax-elixr-b-text/saved_model.pb"`, + }, deepforest: { prettyLabel: "DeepForest", repoName: "deepforest", @@ -173,6 +180,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { snippets: snippets.depth_pro, filter: false, }, + "derm-foundation": { + prettyLabel: "Derm Foundation", + repoName: "derm-foundation", + repoUrl: "https://github.com/google-health/derm-foundation", + filter: false, + countDownloads: `path:"scin_dataset_precomputed_embeddings.npz" OR path:"saved_model.pb"`, + }, diffree: { prettyLabel: "Diffree", repoName: "Diffree", From 160266585ca556450a25e8f035008397ffe061ec Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 27 Nov 2024 10:38:13 +0000 Subject: [PATCH 66/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 7bc2fcda2..410750b95 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.6", + "version": "0.13.7", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From fa66cb3a652dda59f86b97d56a6420a77e2daa4e Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Wed, 27 Nov 2024 13:12:11 +0100 Subject: [PATCH 67/97] =?UTF-8?q?=F0=9F=90=9B=20Fix=20TS=20checking=20on?= =?UTF-8?q?=20tasks-gen=20(#1051)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure why, it doesn't work since https://github.com/huggingface/huggingface.js/pull/1046 --- packages/tasks-gen/tsconfig.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/tasks-gen/tsconfig.json diff --git a/packages/tasks-gen/tsconfig.json b/packages/tasks-gen/tsconfig.json new file mode 100644 index 000000000..b4441ee9b --- /dev/null +++ b/packages/tasks-gen/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "lib": ["ES2022", "DOM"], + "module": "NodeNext", + "target": "ESNext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "skipLibCheck": true, + "noImplicitOverride": true, + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "types": ["vitest/importMeta"] + }, + "include": ["scripts"], + "exclude": ["dist"] +} From 7a78221f93a7a421f99218d55b807bac1870557d Mon Sep 17 00:00:00 2001 From: Lain <70411813+not-lain@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:58:35 +0100 Subject: [PATCH 68/97] update peft code snippet (#1048) this pr fixes #1047 --- packages/tasks/src/model-libraries-snippets.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index bb6ac12c3..3dc520e0c 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -933,10 +933,9 @@ export const peft = (model: ModelData): string[] => { } return [ - `from peft import PeftModel, PeftConfig + `from peft import PeftModel from transformers import AutoModelFor${pefttask} -config = PeftConfig.from_pretrained("${model.id}") base_model = AutoModelFor${pefttask}.from_pretrained("${peftBaseModel}") model = PeftModel.from_pretrained(base_model, "${model.id}")`, ]; From dfdcd88b7af41779e2348abbd5b9341895921989 Mon Sep 17 00:00:00 2001 From: machineuser Date: Wed, 27 Nov 2024 14:59:19 +0000 Subject: [PATCH 69/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 410750b95..d407c8fa0 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.7", + "version": "0.13.8", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 2a99455d3ee66a6f620eda2d35792ac1cff94f4a Mon Sep 17 00:00:00 2001 From: machineuser Date: Mon, 2 Dec 2024 10:56:07 +0000 Subject: [PATCH 70/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index d407c8fa0..4239d6e3e 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.8", + "version": "0.13.9", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From a418861d6b5e05e9ca2b32eb61ed8bdeee91a5ec Mon Sep 17 00:00:00 2001 From: Thibault Goehringer Date: Mon, 2 Dec 2024 18:16:30 +0100 Subject: [PATCH 71/97] Add missing parameters for Table Question Answering (#1053) cf. https://huggingface.co/docs/transformers/v4.46.3/en/main_classes/pipelines#transformers.TableQuestionAnsweringPipeline Slack conversation: https://huggingface.slack.com/archives/C069KSP486B/p1728922203824619 --- .../table-question-answering/inference.ts | 28 +++++++++++++++++-- .../table-question-answering/spec/input.json | 19 ++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/packages/tasks/src/tasks/table-question-answering/inference.ts b/packages/tasks/src/tasks/table-question-answering/inference.ts index 65e7afbfc..18339e033 100644 --- a/packages/tasks/src/tasks/table-question-answering/inference.ts +++ b/packages/tasks/src/tasks/table-question-answering/inference.ts @@ -14,9 +14,7 @@ export interface TableQuestionAnsweringInput { /** * Additional inference parameters for Table Question Answering */ - parameters?: { - [key: string]: unknown; - }; + parameters?: TableQuestionAnsweringParameters; [property: string]: unknown; } /** @@ -35,6 +33,30 @@ export interface TableQuestionAnsweringInputData { }; [property: string]: unknown; } +/** + * Additional inference parameters for Table Question Answering + */ +export interface TableQuestionAnsweringParameters { + /** + * Activates and controls padding. + */ + padding?: Padding; + /** + * Whether to do inference sequentially or as a batch. Batching is faster, but models like + * SQA require the inference to be done sequentially to extract relations within sequences, + * given their conversational nature. + */ + sequential?: boolean; + /** + * Activates and controls truncation. + */ + truncation?: boolean; + [property: string]: unknown; +} +/** + * Activates and controls padding. + */ +export type Padding = "do_not_pad" | "longest" | "max_length"; export type TableQuestionAnsweringOutput = TableQuestionAnsweringOutputElement[]; /** * Outputs of inference for the Table Question Answering task diff --git a/packages/tasks/src/tasks/table-question-answering/spec/input.json b/packages/tasks/src/tasks/table-question-answering/spec/input.json index ab04107cc..86bc400e8 100644 --- a/packages/tasks/src/tasks/table-question-answering/spec/input.json +++ b/packages/tasks/src/tasks/table-question-answering/spec/input.json @@ -36,7 +36,24 @@ "TableQuestionAnsweringParameters": { "title": "TableQuestionAnsweringParameters", "type": "object", - "properties": {} + "properties": { + "padding": { + "type": "string", + "default": "do_not_pad", + "description": "Activates and controls padding.", + "enum": ["do_not_pad", "longest", "max_length"] + }, + "sequential": { + "type": "boolean", + "default": "false", + "description": "Whether to do inference sequentially or as a batch. Batching is faster, but models like SQA require the inference to be done sequentially to extract relations within sequences, given their conversational nature.", + }, + "truncation": { + "type": "boolean", + "default": "false", + "description": "Activates and controls truncation.", + } + } } }, "required": ["inputs"] From 1f6fa4af543ed36a031cc515224dbd34c505b919 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Tue, 3 Dec 2024 11:46:47 +0100 Subject: [PATCH 72/97] Fix lint (#1059) --- .../tasks/src/tasks/table-question-answering/spec/input.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tasks/src/tasks/table-question-answering/spec/input.json b/packages/tasks/src/tasks/table-question-answering/spec/input.json index 86bc400e8..67cc18eae 100644 --- a/packages/tasks/src/tasks/table-question-answering/spec/input.json +++ b/packages/tasks/src/tasks/table-question-answering/spec/input.json @@ -46,12 +46,12 @@ "sequential": { "type": "boolean", "default": "false", - "description": "Whether to do inference sequentially or as a batch. Batching is faster, but models like SQA require the inference to be done sequentially to extract relations within sequences, given their conversational nature.", + "description": "Whether to do inference sequentially or as a batch. Batching is faster, but models like SQA require the inference to be done sequentially to extract relations within sequences, given their conversational nature." }, "truncation": { "type": "boolean", "default": "false", - "description": "Activates and controls truncation.", + "description": "Activates and controls truncation." } } } From d891fc577f20c4cdc848de04b5095714886a5f82 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Tue, 3 Dec 2024 14:34:19 +0100 Subject: [PATCH 73/97] @huggingface/blob and @huggingface/dduf packages (#1058) I really couldn't get https://github.com/huggingface/huggingface.js/pull/1054 to work so I copied over `@huggingface/hub` to a new folder and removed stuff, and it works now :shrug: In follow up PR we may want to make this package a dependency of `@huggingface/hub` and `@huggingface/gguf` (cc @mishig25 @ngxson) See also https://huggingface.co/spaces/DDUF/dduf-check --------- Co-authored-by: Mishig --- .github/workflows/blob-publish.yml | 70 ++++++ .github/workflows/dduf-publish.yml | 73 ++++++ packages/blob/.eslintignore | 2 + packages/blob/.prettierignore | 5 + packages/blob/LICENSE | 21 ++ packages/blob/README.md | 90 ++++++++ packages/blob/index.ts | 1 + packages/blob/package.json | 64 ++++++ packages/blob/pnpm-lock.yaml | 22 ++ packages/blob/src/index.ts | 1 + packages/blob/src/utils/FileBlob.spec.ts | 45 ++++ packages/blob/src/utils/FileBlob.ts | 118 ++++++++++ packages/blob/src/utils/WebBlob.spec.ts | 83 +++++++ packages/blob/src/utils/WebBlob.ts | 111 +++++++++ packages/blob/src/utils/createBlob.ts | 30 +++ packages/blob/src/utils/isBackend.ts | 6 + packages/blob/src/utils/isFrontend.ts | 3 + packages/blob/tsconfig.json | 20 ++ packages/blob/tsup.config.ts | 25 ++ packages/blob/vitest-browser.config.mts | 7 + packages/dduf/.eslintignore | 2 + packages/dduf/.prettierignore | 4 + packages/dduf/LICENSE | 21 ++ packages/dduf/README.md | 33 +++ packages/dduf/index.ts | 1 + packages/dduf/package.json | 58 +++++ packages/dduf/pnpm-lock.yaml | 27 +++ packages/dduf/src/check-dduf.spec.ts | 178 +++++++++++++++ packages/dduf/src/check-dduf.ts | 216 ++++++++++++++++++ packages/dduf/src/check-filename.ts | 17 ++ packages/dduf/src/index.ts | 1 + packages/dduf/tsconfig.json | 20 ++ packages/dduf/tsup.config.ts | 25 ++ packages/hub/src/lib/cache-management.ts | 2 +- packages/hub/src/lib/dataset-info.spec.ts | 10 +- packages/hub/src/lib/dataset-info.ts | 4 +- .../lib/download-file-to-cache-dir.spec.ts | 152 ++++++------ .../hub/src/lib/download-file-to-cache-dir.ts | 4 +- packages/hub/src/lib/download-file.spec.ts | 22 +- packages/hub/src/lib/model-info.spec.ts | 6 +- packages/hub/src/lib/model-info.ts | 4 +- packages/hub/src/lib/paths-info.spec.ts | 10 +- packages/hub/src/lib/paths-info.ts | 62 ++--- packages/hub/src/lib/space-info.spec.ts | 14 +- packages/hub/src/lib/space-info.ts | 4 +- packages/tasks-gen/.prettierignore | 5 + packages/tasks-gen/README.md | 2 +- pnpm-workspace.yaml | 2 + 48 files changed, 1567 insertions(+), 136 deletions(-) create mode 100644 .github/workflows/blob-publish.yml create mode 100644 .github/workflows/dduf-publish.yml create mode 100644 packages/blob/.eslintignore create mode 100644 packages/blob/.prettierignore create mode 100644 packages/blob/LICENSE create mode 100644 packages/blob/README.md create mode 100644 packages/blob/index.ts create mode 100644 packages/blob/package.json create mode 100644 packages/blob/pnpm-lock.yaml create mode 100644 packages/blob/src/index.ts create mode 100644 packages/blob/src/utils/FileBlob.spec.ts create mode 100644 packages/blob/src/utils/FileBlob.ts create mode 100644 packages/blob/src/utils/WebBlob.spec.ts create mode 100644 packages/blob/src/utils/WebBlob.ts create mode 100644 packages/blob/src/utils/createBlob.ts create mode 100644 packages/blob/src/utils/isBackend.ts create mode 100644 packages/blob/src/utils/isFrontend.ts create mode 100644 packages/blob/tsconfig.json create mode 100644 packages/blob/tsup.config.ts create mode 100644 packages/blob/vitest-browser.config.mts create mode 100644 packages/dduf/.eslintignore create mode 100644 packages/dduf/.prettierignore create mode 100644 packages/dduf/LICENSE create mode 100644 packages/dduf/README.md create mode 100644 packages/dduf/index.ts create mode 100644 packages/dduf/package.json create mode 100644 packages/dduf/pnpm-lock.yaml create mode 100644 packages/dduf/src/check-dduf.spec.ts create mode 100644 packages/dduf/src/check-dduf.ts create mode 100644 packages/dduf/src/check-filename.ts create mode 100644 packages/dduf/src/index.ts create mode 100644 packages/dduf/tsconfig.json create mode 100644 packages/dduf/tsup.config.ts create mode 100644 packages/tasks-gen/.prettierignore diff --git a/.github/workflows/blob-publish.yml b/.github/workflows/blob-publish.yml new file mode 100644 index 000000000..a19e395cc --- /dev/null +++ b/.github/workflows/blob-publish.yml @@ -0,0 +1,70 @@ +name: Blob - Version and Release + +on: + workflow_dispatch: + inputs: + newversion: + type: choice + description: "Semantic Version Bump Type" + default: patch + options: + - patch + - minor + - major + +concurrency: + group: "push-to-main" + +defaults: + run: + working-directory: packages/blob + +jobs: + version_and_release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + # Needed to push the tag and the commit on the main branch, otherwise we get: + # > Run git push --follow-tags + # remote: error: GH006: Protected branch update failed for refs/heads/main. + # remote: error: Changes must be made through a pull request. Required status check "lint" is expected. + token: ${{ secrets.BOT_ACCESS_TOKEN }} + - run: corepack enable + - uses: actions/setup-node@v3 + with: + node-version: "20" + cache: "pnpm" + cache-dependency-path: | + packages/blob/pnpm-lock.yaml + # setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED + registry-url: "https://registry.npmjs.org" + - run: pnpm install + - run: git config --global user.name machineuser + - run: git config --global user.email infra+machineuser@huggingface.co + - run: | + PACKAGE_VERSION=$(node -p "require('./package.json').version") + BUMPED_VERSION=$(node -p "require('semver').inc('$PACKAGE_VERSION', '${{ github.event.inputs.newversion }}')") + # Update package.json with the new version + node -e "const fs = require('fs'); const package = JSON.parse(fs.readFileSync('./package.json')); package.version = '$BUMPED_VERSION'; fs.writeFileSync('./package.json', JSON.stringify(package, null, '\t') + '\n');" + git commit . -m "🔖 @huggingface/blob $BUMPED_VERSION" + git tag "blob-v$BUMPED_VERSION" + + - run: pnpm publish --no-git-checks . + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - run: git pull --rebase && git push --follow-tags + # hack - reuse actions/setup-node@v3 just to set a new registry + - uses: actions/setup-node@v3 + with: + node-version: "20" + registry-url: "https://npm.pkg.github.com" + # Disable for now, until github supports PATs for writing github packages (https://github.com/github/roadmap/issues/558) + # - run: pnpm publish --no-git-checks . + # env: + # NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: "Update Doc" + uses: peter-evans/repository-dispatch@v2 + with: + event-type: doc-build + token: ${{ secrets.BOT_ACCESS_TOKEN }} diff --git a/.github/workflows/dduf-publish.yml b/.github/workflows/dduf-publish.yml new file mode 100644 index 000000000..8d543d03e --- /dev/null +++ b/.github/workflows/dduf-publish.yml @@ -0,0 +1,73 @@ +name: DDUF - Version and Release + +on: + workflow_dispatch: + inputs: + newversion: + type: choice + description: "Semantic Version Bump Type" + default: patch + options: + - patch + - minor + - major + +concurrency: + group: "push-to-main" + +defaults: + run: + working-directory: packages/dduf + +jobs: + version_and_release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + # Needed to push the tag and the commit on the main branch, otherwise we get: + # > Run git push --follow-tags + # remote: error: GH006: Protected branch update failed for refs/heads/main. + # remote: error: Changes must be made through a pull request. Required status check "lint" is expected. + token: ${{ secrets.BOT_ACCESS_TOKEN }} + - run: corepack enable + - uses: actions/setup-node@v3 + with: + node-version: "20" + cache: "pnpm" + cache-dependency-path: | + packages/dduf/pnpm-lock.yaml + # setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED + registry-url: "https://registry.npmjs.org" + - run: pnpm install + - run: git config --global user.name machineuser + - run: git config --global user.email infra+machineuser@huggingface.co + - run: | + PACKAGE_VERSION=$(node -p "require('./package.json').version") + BUMPED_VERSION=$(node -p "require('semver').inc('$PACKAGE_VERSION', '${{ github.event.inputs.newversion }}')") + # Update package.json with the new version + node -e "const fs = require('fs'); const package = JSON.parse(fs.readFileSync('./package.json')); package.version = '$BUMPED_VERSION'; fs.writeFileSync('./package.json', JSON.stringify(package, null, '\t') + '\n');" + git commit . -m "🔖 @huggingface/dduf $BUMPED_VERSION" + git tag "dduf-v$BUMPED_VERSION" + + - name: "Check Deps are published before publishing this package" + run: pnpm -w check-deps blob + + - run: pnpm publish --no-git-checks . + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - run: git pull --rebase && git push --follow-tags + # hack - reuse actions/setup-node@v3 just to set a new registry + - uses: actions/setup-node@v3 + with: + node-version: "20" + registry-url: "https://npm.pkg.github.com" + # Disable for now, until github supports PATs for writing github packages (https://github.com/github/roadmap/issues/558) + # - run: pnpm publish --no-git-checks . + # env: + # NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: "Update Doc" + uses: peter-evans/repository-dispatch@v2 + with: + event-type: doc-build + token: ${{ secrets.BOT_ACCESS_TOKEN }} diff --git a/packages/blob/.eslintignore b/packages/blob/.eslintignore new file mode 100644 index 000000000..67c4f0d9d --- /dev/null +++ b/packages/blob/.eslintignore @@ -0,0 +1,2 @@ +dist +sha256.js diff --git a/packages/blob/.prettierignore b/packages/blob/.prettierignore new file mode 100644 index 000000000..4fafcf634 --- /dev/null +++ b/packages/blob/.prettierignore @@ -0,0 +1,5 @@ +pnpm-lock.yaml +# In order to avoid code samples to have tabs, they don't display well on npm +README.md +dist +sha256.js \ No newline at end of file diff --git a/packages/blob/LICENSE b/packages/blob/LICENSE new file mode 100644 index 000000000..5e9693e35 --- /dev/null +++ b/packages/blob/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hugging Face + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/blob/README.md b/packages/blob/README.md new file mode 100644 index 000000000..84ebce19c --- /dev/null +++ b/packages/blob/README.md @@ -0,0 +1,90 @@ +# 🤗 Hugging Face Blobs + +Utilities to convert a string or URL to a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object, whether it represents a local file or a remote URL. + +`fetch` already returns a `Blob` object for remote URLs, but it loads the entire file in memory. This utility makes ad-hoc http range requests when calling `.slice()` on the blob. + +## Install + +```console +pnpm add @huggingface/blob + +npm add @huggingface/blob + +yarn add @huggingface/blob +``` + +### Deno + +```ts +// esm.sh +import { FileBlob } from "https://esm.sh/@huggingface/blob/FileBlob"; +import { WebBlob } from "https://esm.sh/@huggingface/blob/WebBlob"; +import { createBlob } from "https://esm.sh/@huggingface/blob"; +// or npm: +import { FileBlob } from "npm:@huggingface/blob/FileBlob"; +import { WebBlob } from "npm:@huggingface/blob/WebBlob"; +import { createBlob } from "npm:@huggingface/blob"; +``` + +## Usage + + +```ts +import { FileBlob } from "@huggingface/blob/FileBlob"; +import { WebBlob } from "@huggingface/blob/WebBlob"; +import { createBlob } from "@huggingface/blob"; + +const fileBlob = await FileBlob.create("path/to/file"); +const webBlob = await WebBlob.create("https://url/to/file"); + +const blob = await createBlob("..."); // Automatically detects if it's a file or web URL +``` + +## API + +### createBlob + +Creates a Blob object from a string or URL. Automatically detects if it's a file or web URL. + +```ts +await createBlob("...", { + /** + * Custom fetch function to use, in case it resolves to a Web Blob. + * + * Useful for adding headers, etc. + */ + fetch: ..., +}); + +### FileBlob + +```ts +await FileBlob.create("path/to/file"); +await FileBlob.create(new URL("file:///path/to/file")); +``` + +### WebBlob + +Creates a Blob object from a URL. If the file is less than 1MB (as indicated by the Content-Length header), by default it will be cached in memory in entirety upon blob creation. + +This class is useful for large files that do not need to be loaded all at once in memory, as it makes range requests for the data. + +```ts +await WebBlob.create("https://url/to/file"); +await WebBlob.create(new URL("https://url/to/file")); + +await WebBlob.create("https://url/to/file", { + /** + * Custom fetch function to use. Useful for adding headers, etc. + */ + fetch: ..., + /** + * If the file is less than the specified size, it will be cached in memory in entirety upon blob creation, + * instead of doing range requests for the data. + * + * @default 1_000_000 + */ + cacheBelow: ... +}) +``` \ No newline at end of file diff --git a/packages/blob/index.ts b/packages/blob/index.ts new file mode 100644 index 000000000..e910bb060 --- /dev/null +++ b/packages/blob/index.ts @@ -0,0 +1 @@ +export * from "./src/index"; diff --git a/packages/blob/package.json b/packages/blob/package.json new file mode 100644 index 000000000..26c989be2 --- /dev/null +++ b/packages/blob/package.json @@ -0,0 +1,64 @@ +{ + "name": "@huggingface/blob", + "packageManager": "pnpm@8.10.5", + "version": "0.0.1", + "description": "Utilities to convert URLs and files to Blobs, internally used by Hugging Face libs", + "repository": "https://github.com/huggingface/huggingface.js.git", + "publishConfig": { + "access": "public" + }, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs" + }, + "./package.json": "./package.json", + "./WebBlob": { + "require": "./dist/src/utils/WebBlob.js", + "import": "./dist/src/utils/WebBlob.mjs" + }, + "./FileBlob": { + "require": "./dist/src/utils/FileBlob.js", + "import": "./dist/src/utils/FileBlob.mjs" + } + }, + "browser": { + "./src/utils/FileBlob.ts": false, + "./dist/index.js": "./dist/browser/index.js", + "./dist/index.mjs": "./dist/browser/index.mjs" + }, + "source": "index.ts", + "scripts": { + "lint": "eslint --quiet --fix --ext .cjs,.ts .", + "lint:check": "eslint --ext .cjs,.ts .", + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepublishOnly": "pnpm run build", + "build": "tsup && tsc --emitDeclarationOnly --declaration && cp dist/index.d.ts dist/index.m.d.ts && cp dist/src/utils/FileBlob.d.ts dist/src/utils/FileBlob.m.d.ts && cp dist/src/utils/WebBlob.d.ts dist/src/utils/WebBlob.m.d.ts", + "prepare": "pnpm run build", + "test": "vitest run", + "test:browser": "vitest run --browser.name=chrome --browser.headless --config vitest-browser.config.mts", + "check": "tsc" + }, + "files": [ + "src", + "dist", + "index.ts", + "tsconfig.json" + ], + "keywords": [ + "huggingface", + "hugging", + "face", + "blob", + "lazy" + ], + "author": "Hugging Face", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.11.28" + } +} diff --git a/packages/blob/pnpm-lock.yaml b/packages/blob/pnpm-lock.yaml new file mode 100644 index 000000000..f8939bbbb --- /dev/null +++ b/packages/blob/pnpm-lock.yaml @@ -0,0 +1,22 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +devDependencies: + '@types/node': + specifier: ^20.11.28 + version: 20.11.28 + +packages: + + /@types/node@20.11.28: + resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==} + dependencies: + undici-types: 5.26.5 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true diff --git a/packages/blob/src/index.ts b/packages/blob/src/index.ts new file mode 100644 index 000000000..eadd56ab8 --- /dev/null +++ b/packages/blob/src/index.ts @@ -0,0 +1 @@ +export { createBlob } from "./utils/createBlob"; diff --git a/packages/blob/src/utils/FileBlob.spec.ts b/packages/blob/src/utils/FileBlob.spec.ts new file mode 100644 index 000000000..2ed51d8e3 --- /dev/null +++ b/packages/blob/src/utils/FileBlob.spec.ts @@ -0,0 +1,45 @@ +import { open, stat } from "node:fs/promises"; +import { TextDecoder } from "node:util"; +import { describe, expect, it } from "vitest"; +import { FileBlob } from "./FileBlob"; + +describe("FileBlob", () => { + it("should create a FileBlob with a slice on the entire file", async () => { + const file = await open("package.json", "r"); + const { size } = await stat("package.json"); + + const fileBlob = await FileBlob.create("package.json"); + + expect(fileBlob).toMatchObject({ + path: "package.json", + start: 0, + end: size, + }); + expect(fileBlob.size).toBe(size); + expect(fileBlob.type).toBe(""); + const text = await fileBlob.text(); + const expectedText = (await file.read(Buffer.alloc(size), 0, size)).buffer.toString("utf8"); + expect(text).toBe(expectedText); + const result = await fileBlob.stream().getReader().read(); + expect(new TextDecoder().decode(result.value)).toBe(expectedText); + }); + + it("should create a slice on the file", async () => { + const file = await open("package.json", "r"); + const fileBlob = await FileBlob.create("package.json"); + + const slice = fileBlob.slice(10, 20); + + expect(slice).toMatchObject({ + path: "package.json", + start: 10, + end: 20, + }); + expect(slice.size).toBe(10); + const sliceText = await slice.text(); + const expectedText = (await file.read(Buffer.alloc(10), 0, 10, 10)).buffer.toString("utf8"); + expect(sliceText).toBe(expectedText); + const result = await slice.stream().getReader().read(); + expect(new TextDecoder().decode(result.value)).toBe(expectedText); + }); +}); diff --git a/packages/blob/src/utils/FileBlob.ts b/packages/blob/src/utils/FileBlob.ts new file mode 100644 index 000000000..e783ca6fa --- /dev/null +++ b/packages/blob/src/utils/FileBlob.ts @@ -0,0 +1,118 @@ +import { createReadStream } from "node:fs"; +import { open, stat } from "node:fs/promises"; +import { Readable } from "node:stream"; +import type { FileHandle } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; + +/** + * @internal + * + * A FileBlob is a replacement for the Blob class that allows to lazy read files + * in order to preserve memory. + * + * It is a drop-in replacement for the Blob class, so you can use it as a Blob. + * + * The main difference is the instantiation, which is done asynchronously using the `FileBlob.create` method. + * + * @example + * const fileBlob = await FileBlob.create("path/to/package.json"); + * + * await fetch("https://aschen.tech", { method: "POST", body: fileBlob }); + */ +export class FileBlob extends Blob { + /** + * Creates a new FileBlob on the provided file. + * + * @param path Path to the file to be lazy readed + */ + static async create(path: string | URL): Promise { + path = path instanceof URL ? fileURLToPath(path) : path; + + const { size } = await stat(path); + + const fileBlob = new FileBlob(path, 0, size); + + return fileBlob; + } + + private path: string; + private start: number; + private end: number; + + private constructor(path: string, start: number, end: number) { + super(); + + this.path = path; + this.start = start; + this.end = end; + } + + /** + * Returns the size of the blob. + */ + override get size(): number { + return this.end - this.start; + } + + /** + * Returns a new instance of FileBlob that is a slice of the current one. + * + * The slice is inclusive of the start and exclusive of the end. + * + * The slice method does not supports negative start/end. + * + * @param start beginning of the slice + * @param end end of the slice + */ + override slice(start = 0, end = this.size): FileBlob { + if (start < 0 || end < 0) { + new TypeError("Unsupported negative start/end on FileBlob.slice"); + } + + const slice = new FileBlob(this.path, this.start + start, Math.min(this.start + end, this.end)); + + return slice; + } + + /** + * Read the part of the file delimited by the FileBlob and returns it as an ArrayBuffer. + */ + override async arrayBuffer(): Promise { + const slice = await this.execute((file) => file.read(Buffer.alloc(this.size), 0, this.size, this.start)); + + return slice.buffer; + } + + /** + * Read the part of the file delimited by the FileBlob and returns it as a string. + */ + override async text(): Promise { + const buffer = (await this.arrayBuffer()) as Buffer; + + return buffer.toString("utf8"); + } + + /** + * Returns a stream around the part of the file delimited by the FileBlob. + */ + override stream(): ReturnType { + return Readable.toWeb(createReadStream(this.path, { start: this.start, end: this.end - 1 })) as ReturnType< + Blob["stream"] + >; + } + + /** + * We are opening and closing the file for each action to prevent file descriptor leaks. + * + * It is an intended choice of developer experience over performances. + */ + private async execute(action: (file: FileHandle) => Promise) { + const file = await open(this.path, "r"); + + try { + return await action(file); + } finally { + await file.close(); + } + } +} diff --git a/packages/blob/src/utils/WebBlob.spec.ts b/packages/blob/src/utils/WebBlob.spec.ts new file mode 100644 index 000000000..919c8f019 --- /dev/null +++ b/packages/blob/src/utils/WebBlob.spec.ts @@ -0,0 +1,83 @@ +import { describe, expect, it, beforeAll } from "vitest"; +import { WebBlob } from "./WebBlob"; + +describe("WebBlob", () => { + const resourceUrl = new URL("https://huggingface.co/spaces/aschen/push-model-from-web/raw/main/mobilenet/model.json"); + let fullText: string; + let size: number; + let contentType: string; + + beforeAll(async () => { + const response = await fetch(resourceUrl, { method: "HEAD" }); + size = Number(response.headers.get("content-length")); + contentType = response.headers.get("content-type") || ""; + fullText = await (await fetch(resourceUrl)).text(); + }); + + it("should create a WebBlob with a slice on the entire resource", async () => { + const webBlob = await WebBlob.create(resourceUrl, { cacheBelow: 0 }); + + expect(webBlob).toMatchObject({ + url: resourceUrl, + start: 0, + end: size, + contentType, + }); + expect(webBlob).toBeInstanceOf(WebBlob); + expect(webBlob.size).toBe(size); + expect(webBlob.type).toBe(contentType); + + const text = await webBlob.text(); + expect(text).toBe(fullText); + + const streamText = await new Response(webBlob.stream()).text(); + expect(streamText).toBe(fullText); + }); + + it("should create a WebBlob with a slice on the entire resource, cached", async () => { + const webBlob = await WebBlob.create(resourceUrl, { cacheBelow: 1_000_000 }); + + expect(webBlob).not.toBeInstanceOf(WebBlob); + expect(webBlob.size).toBe(size); + expect(webBlob.type.replace(/;\s*charset=utf-8/, "")).toBe(contentType.replace(/;\s*charset=utf-8/, "")); + + const text = await webBlob.text(); + expect(text).toBe(fullText); + + const streamText = await new Response(webBlob.stream()).text(); + expect(streamText).toBe(fullText); + }); + + it("should lazy load a LFS file hosted on Hugging Face", async () => { + const stableDiffusionUrl = + "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/unet/diffusion_pytorch_model.fp16.safetensors"; + const url = new URL(stableDiffusionUrl); + const webBlob = await WebBlob.create(url); + + expect(webBlob.size).toBe(5_135_149_760); + expect(webBlob).toBeInstanceOf(WebBlob); + expect(webBlob).toMatchObject({ url }); + expect(await webBlob.slice(10, 22).text()).toBe("__metadata__"); + }); + + it("should create a slice on the file", async () => { + const expectedText = fullText.slice(10, 20); + + const slice = (await WebBlob.create(resourceUrl, { cacheBelow: 0 })).slice(10, 20); + + expect(slice).toMatchObject({ + url: resourceUrl, + start: 10, + end: 20, + contentType, + }); + expect(slice.size).toBe(10); + expect(slice.type).toBe(contentType); + + const sliceText = await slice.text(); + expect(sliceText).toBe(expectedText); + + const streamText = await new Response(slice.stream()).text(); + expect(streamText).toBe(expectedText); + }); +}); diff --git a/packages/blob/src/utils/WebBlob.ts b/packages/blob/src/utils/WebBlob.ts new file mode 100644 index 000000000..fe35813fe --- /dev/null +++ b/packages/blob/src/utils/WebBlob.ts @@ -0,0 +1,111 @@ +/** + * WebBlob is a Blob implementation for web resources that supports range requests. + */ + +interface WebBlobCreateOptions { + /** + * @default 1_000_000 + * + * Objects below that size will immediately be fetched and put in RAM, rather + * than streamed ad-hoc + */ + cacheBelow?: number; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; +} + +export class WebBlob extends Blob { + static async create(url: URL, opts?: WebBlobCreateOptions): Promise { + const customFetch = opts?.fetch ?? fetch; + const response = await customFetch(url, { method: "HEAD" }); + + const size = Number(response.headers.get("content-length")); + const contentType = response.headers.get("content-type") || ""; + const supportRange = response.headers.get("accept-ranges") === "bytes"; + + if (!supportRange || size < (opts?.cacheBelow ?? 1_000_000)) { + return await (await customFetch(url)).blob(); + } + + return new WebBlob(url, 0, size, contentType, true, customFetch); + } + + private url: URL; + private start: number; + private end: number; + private contentType: string; + private full: boolean; + private fetch: typeof fetch; + + constructor(url: URL, start: number, end: number, contentType: string, full: boolean, customFetch: typeof fetch) { + super([]); + + this.url = url; + this.start = start; + this.end = end; + this.contentType = contentType; + this.full = full; + this.fetch = customFetch; + } + + override get size(): number { + return this.end - this.start; + } + + override get type(): string { + return this.contentType; + } + + override slice(start = 0, end = this.size): WebBlob { + if (start < 0 || end < 0) { + new TypeError("Unsupported negative start/end on FileBlob.slice"); + } + + const slice = new WebBlob( + this.url, + this.start + start, + Math.min(this.start + end, this.end), + this.contentType, + start === 0 && end === this.size ? this.full : false, + this.fetch + ); + + return slice; + } + + override async arrayBuffer(): Promise { + const result = await this.fetchRange(); + + return result.arrayBuffer(); + } + + override async text(): Promise { + const result = await this.fetchRange(); + + return result.text(); + } + + override stream(): ReturnType { + const stream = new TransformStream(); + + this.fetchRange() + .then((response) => response.body?.pipeThrough(stream)) + .catch((error) => stream.writable.abort(error.message)); + + return stream.readable; + } + + private fetchRange(): Promise { + const fetch = this.fetch; // to avoid this.fetch() which is bound to the instance instead of globalThis + if (this.full) { + return fetch(this.url); + } + return fetch(this.url, { + headers: { + Range: `bytes=${this.start}-${this.end - 1}`, + }, + }); + } +} diff --git a/packages/blob/src/utils/createBlob.ts b/packages/blob/src/utils/createBlob.ts new file mode 100644 index 000000000..0cf54206d --- /dev/null +++ b/packages/blob/src/utils/createBlob.ts @@ -0,0 +1,30 @@ +import { WebBlob } from "./WebBlob"; +import { isFrontend } from "./isFrontend"; + +/** + * This function allow to retrieve either a FileBlob or a WebBlob from a URL. + * + * From the backend: + * - support local files + * - support http resources with absolute URLs + * + * From the frontend: + * - support http resources with absolute or relative URLs + */ +export async function createBlob(url: URL, opts?: { fetch?: typeof fetch }): Promise { + if (url.protocol === "http:" || url.protocol === "https:") { + return WebBlob.create(url, { fetch: opts?.fetch }); + } + + if (isFrontend) { + throw new TypeError(`Unsupported URL protocol "${url.protocol}"`); + } + + if (url.protocol === "file:") { + const { FileBlob } = await import("./FileBlob"); + + return FileBlob.create(url); + } + + throw new TypeError(`Unsupported URL protocol "${url.protocol}"`); +} diff --git a/packages/blob/src/utils/isBackend.ts b/packages/blob/src/utils/isBackend.ts new file mode 100644 index 000000000..1e6f27998 --- /dev/null +++ b/packages/blob/src/utils/isBackend.ts @@ -0,0 +1,6 @@ +const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; + +const isWebWorker = + typeof self === "object" && self.constructor && self.constructor.name === "DedicatedWorkerGlobalScope"; + +export const isBackend = !isBrowser && !isWebWorker; diff --git a/packages/blob/src/utils/isFrontend.ts b/packages/blob/src/utils/isFrontend.ts new file mode 100644 index 000000000..0b9bab392 --- /dev/null +++ b/packages/blob/src/utils/isFrontend.ts @@ -0,0 +1,3 @@ +import { isBackend } from "./isBackend"; + +export const isFrontend = !isBackend; diff --git a/packages/blob/tsconfig.json b/packages/blob/tsconfig.json new file mode 100644 index 000000000..254606a30 --- /dev/null +++ b/packages/blob/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "lib": ["ES2022", "DOM"], + "module": "CommonJS", + "moduleResolution": "node", + "target": "ES2022", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "skipLibCheck": true, + "noImplicitOverride": true, + "outDir": "./dist", + "declaration": true, + "declarationMap": true + }, + "include": ["src", "index.ts"], + "exclude": ["dist"] +} diff --git a/packages/blob/tsup.config.ts b/packages/blob/tsup.config.ts new file mode 100644 index 000000000..c08bf2a12 --- /dev/null +++ b/packages/blob/tsup.config.ts @@ -0,0 +1,25 @@ +import type { Options } from "tsup"; + +const baseConfig: Options = { + entry: ["./index.ts"], + format: ["cjs", "esm"], + outDir: "dist", + clean: true, +}; + +const nodeConfig: Options = { + ...baseConfig, + entry: ["./index.ts", "./src/utils/WebBlob.ts", "./src/utils/FileBlob.ts"], + platform: "node", +}; + +const browserConfig: Options = { + ...baseConfig, + entry: ["./index.ts", "./src/utils/WebBlob.ts"], + platform: "browser", + target: "es2018", + splitting: true, + outDir: "dist/browser", +}; + +export default [nodeConfig, browserConfig]; diff --git a/packages/blob/vitest-browser.config.mts b/packages/blob/vitest-browser.config.mts new file mode 100644 index 000000000..65be77c7a --- /dev/null +++ b/packages/blob/vitest-browser.config.mts @@ -0,0 +1,7 @@ +import { configDefaults, defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, "src/utils/FileBlob.spec.ts"], + }, +}); diff --git a/packages/dduf/.eslintignore b/packages/dduf/.eslintignore new file mode 100644 index 000000000..67c4f0d9d --- /dev/null +++ b/packages/dduf/.eslintignore @@ -0,0 +1,2 @@ +dist +sha256.js diff --git a/packages/dduf/.prettierignore b/packages/dduf/.prettierignore new file mode 100644 index 000000000..cac0c6949 --- /dev/null +++ b/packages/dduf/.prettierignore @@ -0,0 +1,4 @@ +pnpm-lock.yaml +# In order to avoid code samples to have tabs, they don't display well on npm +README.md +dist \ No newline at end of file diff --git a/packages/dduf/LICENSE b/packages/dduf/LICENSE new file mode 100644 index 000000000..5e9693e35 --- /dev/null +++ b/packages/dduf/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hugging Face + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/dduf/README.md b/packages/dduf/README.md new file mode 100644 index 000000000..993333965 --- /dev/null +++ b/packages/dduf/README.md @@ -0,0 +1,33 @@ +# 🤗 Hugging Face DDUF + +Very alpha version of a DDUF checker / parser. + +## Install + +```console +pnpm add @huggingface/dduf + +npm add @huggingface/dduf + +yarn add @huggingface/dduf +``` + +### Deno + +```ts +// esm.sh +import { checkDDUF } from "https://esm.sh/@huggingface/dduf"; +// or npm: +import { checkDDUF } from "npm:@huggingface/dduf"; +``` + +## Usage + + +```ts +import { checkDDUF } from "@huggingface/dduf"; + +for await (const entry of checkDDUF(URL | Blob, { log: console.log })) { + console.log("file", entry); +} +``` diff --git a/packages/dduf/index.ts b/packages/dduf/index.ts new file mode 100644 index 000000000..3bd16e178 --- /dev/null +++ b/packages/dduf/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/packages/dduf/package.json b/packages/dduf/package.json new file mode 100644 index 000000000..61b6330a8 --- /dev/null +++ b/packages/dduf/package.json @@ -0,0 +1,58 @@ +{ + "name": "@huggingface/dduf", + "packageManager": "pnpm@8.10.5", + "version": "0.0.1", + "description": "Very alpha lib to check DDUF compliance", + "repository": "https://github.com/huggingface/huggingface.js.git", + "publishConfig": { + "access": "public" + }, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.mjs" + }, + "./package.json": "./package.json" + }, + "browser": { + "./dist/index.js": "./dist/browser/index.js", + "./dist/index.mjs": "./dist/browser/index.mjs" + }, + "source": "index.ts", + "scripts": { + "lint": "eslint --quiet --fix --ext .cjs,.ts .", + "lint:check": "eslint --ext .cjs,.ts .", + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepublishOnly": "pnpm run build", + "build": "tsup && tsc --emitDeclarationOnly --declaration", + "prepare": "pnpm run build", + "test": "vitest run", + "test:browser": "vitest run --browser.name=chrome --browser.headless", + "check": "tsc" + }, + "files": [ + "src", + "dist", + "index.ts", + "tsconfig.json" + ], + "keywords": [ + "huggingface", + "hugging", + "face", + "dduf" + ], + "author": "Hugging Face", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.11.28" + }, + "dependencies": { + "@huggingface/blob": "workspace:^" + } +} diff --git a/packages/dduf/pnpm-lock.yaml b/packages/dduf/pnpm-lock.yaml new file mode 100644 index 000000000..0c7f7196a --- /dev/null +++ b/packages/dduf/pnpm-lock.yaml @@ -0,0 +1,27 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@huggingface/blob': + specifier: workspace:^ + version: link:../blob + +devDependencies: + '@types/node': + specifier: ^20.11.28 + version: 20.17.9 + +packages: + + /@types/node@20.17.9: + resolution: {integrity: sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw==} + dependencies: + undici-types: 6.19.8 + dev: true + + /undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + dev: true diff --git a/packages/dduf/src/check-dduf.spec.ts b/packages/dduf/src/check-dduf.spec.ts new file mode 100644 index 000000000..ad98b9823 --- /dev/null +++ b/packages/dduf/src/check-dduf.spec.ts @@ -0,0 +1,178 @@ +import { describe, expect, it } from "vitest"; +import { checkDDUF, type DDUFFileEntry } from "./check-dduf"; + +describe("check-dduf", () => { + it("should work", async () => { + const files: DDUFFileEntry[] = []; + for await (const file of checkDDUF( + new URL("https://huggingface.co/spaces/coyotte508/dduf-check/resolve/main/file-64.dduf") + )) { + files.push(file); + } + + expect(files).toEqual([ + { + fileHeaderOffset: 0, + name: "vae/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 82, + name: "vae/config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 178, + name: "vae/diffusion_pytorch_model.safetensors", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 295, + name: "text_encoder_2/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 388, + name: "text_encoder_2/config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 495, + name: "text_encoder_2/model-00002-of-00002.safetensors", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 620, + name: "text_encoder_2/models.saftensors.index.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 744, + name: "text_encoder_2/model-00001-of-00002.safetensors", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 869, + name: "transformer/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 959, + name: "transformer/config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 1063, + name: "transformer/diffusion_pytorch_model.safetensors", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 1188, + name: "tokenizer_2/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 1278, + name: "tokenizer_2/vocab.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 1381, + name: "tokenizer_2/special_tokens_map.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 1497, + name: "tokenizer_2/tokenizer_config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 1611, + name: "tokenizer_2/spiece.gguf", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 1712, + name: "tokenizer/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 1800, + name: "tokenizer/vocab.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 1901, + name: "tokenizer/special_tokens_map.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 2015, + name: "tokenizer/tokenizer_config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 2127, + name: "scheduler/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 2215, + name: "scheduler/scheduler-config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 2327, + name: "text_encoder/", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 2418, + name: "text_encoder/config.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 2523, + name: "text_encoder/model-00002-of-00002.safetensors", + size: 0, + type: "file", + }, + { + fileHeaderOffset: 2646, + name: "text_encoder/models.saftensors.index.json", + size: 3, + type: "file", + }, + { + fileHeaderOffset: 2768, + name: "text_encoder/model-00001-of-00002.safetensors", + size: 0, + type: "file", + }, + ]); + }); +}); diff --git a/packages/dduf/src/check-dduf.ts b/packages/dduf/src/check-dduf.ts new file mode 100644 index 000000000..a4f17a959 --- /dev/null +++ b/packages/dduf/src/check-dduf.ts @@ -0,0 +1,216 @@ +import { checkFilename } from "./check-filename"; +import { createBlob } from "@huggingface/blob"; + +export interface DDUFFileEntry { + type: "file"; + name: string; + size: number; + fileHeaderOffset: number; +} + +export async function* checkDDUF(url: Blob | URL, opts?: { log?: (x: string) => void }): AsyncGenerator { + const blob = url instanceof Blob ? url : await createBlob(url); + + opts?.log?.("File size: " + blob.size); + + // DDUF is a zip file, uncompressed. + + const last100kB = await blob.slice(blob.size - 100_000, blob.size).arrayBuffer(); + + const view = new DataView(last100kB); + + let index = view.byteLength - 22; + let found = false; + + while (index >= 0) { + if (view.getUint32(index, true) === 0x06054b50) { + found = true; + break; + } + + index--; + } + + if (!found) { + throw new Error("DDUF footer not found in last 100kB of file"); + } + + opts?.log?.("DDUF footer found at offset " + (blob.size - last100kB.byteLength + index)); + + const diskNumber = view.getUint16(index + 4, true); + + opts?.log?.("Disk number: " + diskNumber); + + if (diskNumber !== 0 && diskNumber !== 0xffff) { + throw new Error("Multi-disk archives not supported"); + } + + let fileCount = view.getUint16(index + 10, true); + let centralDirSize = view.getUint32(index + 12, true); + let centralDirOffset = view.getUint32(index + 16, true); + const isZip64 = centralDirOffset === 0xffffffff; + + opts?.log?.("File count: " + fileCount); + + if (isZip64) { + opts?.log?.("Zip64 format detected"); + + index -= 20; + found = false; + while (index >= 0) { + if (view.getUint32(index, true) === 0x07064b50) { + found = true; + break; + } + + index--; + } + + if (!found) { + throw new Error("Zip64 footer not found in last 100kB of file"); + } + + opts?.log?.("Zip64 footer found at offset " + (blob.size - last100kB.byteLength + index)); + + const diskWithCentralDir = view.getUint32(index + 4, true); + + if (diskWithCentralDir !== 0) { + throw new Error("Multi-disk archives not supported"); + } + + const endCentralDirOffset = Number(view.getBigUint64(index + 8, true)); + + index = endCentralDirOffset - (blob.size - last100kB.byteLength); + + if (index < 0) { + throw new Error("Central directory offset is outside the last 100kB of the file"); + } + + if (view.getUint32(index, true) !== 0x06064b50) { + throw new Error("Invalid central directory header"); + } + + const thisDisk = view.getUint16(index + 16, true); + const centralDirDisk = view.getUint16(index + 20, true); + + if (thisDisk !== 0) { + throw new Error("Multi-disk archives not supported"); + } + + if (centralDirDisk !== 0) { + throw new Error("Multi-disk archives not supported"); + } + + centralDirSize = Number(view.getBigUint64(index + 40, true)); + centralDirOffset = Number(view.getBigUint64(index + 48, true)); + fileCount = Number(view.getBigUint64(index + 32, true)); + + opts?.log?.("File count zip 64: " + fileCount); + } + + opts?.log?.("Central directory size: " + centralDirSize); + opts?.log?.("Central directory offset: " + centralDirOffset); + + const centralDir = + centralDirOffset > blob.size - last100kB.byteLength + ? last100kB.slice( + centralDirOffset - (blob.size - last100kB.byteLength), + centralDirOffset - (blob.size - last100kB.byteLength) + centralDirSize + ) + : await blob.slice(centralDirOffset, centralDirOffset + centralDirSize).arrayBuffer(); + + const centralDirView = new DataView(centralDir); + let offset = 0; + + for (let i = 0; i < fileCount; i++) { + if (centralDirView.getUint32(offset + 0, true) !== 0x02014b50) { + throw new Error("Invalid central directory file header"); + } + + if (offset + 46 > centralDir.byteLength) { + throw new Error("Unexpected end of central directory"); + } + + const compressionMethod = centralDirView.getUint16(offset + 10, true); + + if (compressionMethod !== 0) { + throw new Error("Unsupported compression method: " + compressionMethod); + } + + const filenameLength = centralDirView.getUint16(offset + 28, true); + const fileName = new TextDecoder().decode(new Uint8Array(centralDir, offset + 46, filenameLength)); + + opts?.log?.("File " + i); + opts?.log?.("File name: " + fileName); + + checkFilename(fileName); + + const fileDiskNumber = centralDirView.getUint16(34, true); + + if (fileDiskNumber !== 0 && fileDiskNumber !== 0xffff) { + throw new Error("Multi-disk archives not supported"); + } + + let size = centralDirView.getUint32(offset + 24, true); + let compressedSize = centralDirView.getUint32(offset + 20, true); + let filePosition = centralDirView.getUint32(offset + 42, true); + + const extraFieldLength = centralDirView.getUint16(offset + 30, true); + + if (size === 0xffffffff || compressedSize === 0xffffffff || filePosition === 0xffffffff) { + opts?.log?.("File size is in zip64 format"); + + const extraFields = new DataView(centralDir, offset + 46 + filenameLength, extraFieldLength); + + let extraFieldOffset = 0; + + while (extraFieldOffset < extraFieldLength) { + const headerId = extraFields.getUint16(extraFieldOffset, true); + const extraFieldSize = extraFields.getUint16(extraFieldOffset + 2, true); + if (headerId !== 0x0001) { + extraFieldOffset += 4 + extraFieldSize; + continue; + } + + const zip64ExtraField = new DataView( + centralDir, + offset + 46 + filenameLength + extraFieldOffset + 4, + extraFieldSize + ); + let zip64ExtraFieldOffset = 0; + + if (size === 0xffffffff) { + size = Number(zip64ExtraField.getBigUint64(zip64ExtraFieldOffset, true)); + zip64ExtraFieldOffset += 8; + } + + if (compressedSize === 0xffffffff) { + compressedSize = Number(zip64ExtraField.getBigUint64(zip64ExtraFieldOffset, true)); + zip64ExtraFieldOffset += 8; + } + + if (filePosition === 0xffffffff) { + filePosition = Number(zip64ExtraField.getBigUint64(zip64ExtraFieldOffset, true)); + zip64ExtraFieldOffset += 8; + } + + break; + } + } + + if (size !== compressedSize) { + throw new Error("Compressed size and size differ: " + compressedSize + " vs " + size); + } + opts?.log?.("File size: " + size); + + const commentLength = centralDirView.getUint16(offset + 32, true); + + opts?.log?.("File header position in archive: " + filePosition); + + offset += 46 + filenameLength + extraFieldLength + commentLength; + + yield { type: "file", name: fileName, size, fileHeaderOffset: filePosition }; + } + + opts?.log?.("All files checked"); +} diff --git a/packages/dduf/src/check-filename.ts b/packages/dduf/src/check-filename.ts new file mode 100644 index 000000000..5eba2548c --- /dev/null +++ b/packages/dduf/src/check-filename.ts @@ -0,0 +1,17 @@ +export function checkFilename(filename: string): void { + if ( + !filename.endsWith(".safetensors") && + !filename.endsWith(".json") && + !filename.endsWith(".gguf") && + !filename.endsWith(".txt") && + !filename.endsWith("/") + ) { + throw new Error("Files must have a .safetensors, .txt, .gguf or .json extension"); + } + + const split = filename.split("/"); + + if (split.length > 2) { + throw new Error("Files must be only one level deep, not more"); + } +} diff --git a/packages/dduf/src/index.ts b/packages/dduf/src/index.ts new file mode 100644 index 000000000..ab8badb8e --- /dev/null +++ b/packages/dduf/src/index.ts @@ -0,0 +1 @@ +export * from "./check-dduf"; diff --git a/packages/dduf/tsconfig.json b/packages/dduf/tsconfig.json new file mode 100644 index 000000000..254606a30 --- /dev/null +++ b/packages/dduf/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "lib": ["ES2022", "DOM"], + "module": "CommonJS", + "moduleResolution": "node", + "target": "ES2022", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "skipLibCheck": true, + "noImplicitOverride": true, + "outDir": "./dist", + "declaration": true, + "declarationMap": true + }, + "include": ["src", "index.ts"], + "exclude": ["dist"] +} diff --git a/packages/dduf/tsup.config.ts b/packages/dduf/tsup.config.ts new file mode 100644 index 000000000..8306dcbfc --- /dev/null +++ b/packages/dduf/tsup.config.ts @@ -0,0 +1,25 @@ +import type { Options } from "tsup"; + +const baseConfig: Options = { + entry: ["./index.ts"], + format: ["cjs", "esm"], + outDir: "dist", + clean: true, +}; + +const nodeConfig: Options = { + ...baseConfig, + entry: ["./index.ts"], + platform: "node", +}; + +const browserConfig: Options = { + ...baseConfig, + entry: ["./index.ts"], + platform: "browser", + target: "es2018", + splitting: true, + outDir: "dist/browser", +}; + +export default [nodeConfig, browserConfig]; diff --git a/packages/hub/src/lib/cache-management.ts b/packages/hub/src/lib/cache-management.ts index 98c3be5b4..84b664077 100644 --- a/packages/hub/src/lib/cache-management.ts +++ b/packages/hub/src/lib/cache-management.ts @@ -25,7 +25,7 @@ const FILES_TO_IGNORE: string[] = [".DS_Store"]; export const REPO_ID_SEPARATOR: string = "--"; export function getRepoFolderName({ name, type }: RepoId): string { - const parts = [`${type}s`, ...name.split("/")] + const parts = [`${type}s`, ...name.split("/")]; return parts.join(REPO_ID_SEPARATOR); } diff --git a/packages/hub/src/lib/dataset-info.spec.ts b/packages/hub/src/lib/dataset-info.spec.ts index 982bdcf40..ae235e5e8 100644 --- a/packages/hub/src/lib/dataset-info.spec.ts +++ b/packages/hub/src/lib/dataset-info.spec.ts @@ -20,9 +20,9 @@ describe("datasetInfo", () => { }); it("should return the dataset info with author", async () => { - const info: DatasetEntry & Pick = await datasetInfo({ + const info: DatasetEntry & Pick = await datasetInfo({ name: "nyu-mll/glue", - additionalFields: ['author'], + additionalFields: ["author"], }); expect(info).toEqual({ id: "621ffdd236468d709f181e3f", @@ -32,12 +32,12 @@ describe("datasetInfo", () => { updatedAt: expect.any(Date), likes: expect.any(Number), private: false, - author: 'nyu-mll' + author: "nyu-mll", }); }); it("should return the dataset info for a specific revision", async () => { - const info: DatasetEntry & Pick = await datasetInfo({ + const info: DatasetEntry & Pick = await datasetInfo({ name: "nyu-mll/glue", revision: "cb2099c76426ff97da7aa591cbd317d91fb5fcb7", additionalFields: ["sha"], @@ -50,7 +50,7 @@ describe("datasetInfo", () => { updatedAt: expect.any(Date), likes: expect.any(Number), private: false, - sha: 'cb2099c76426ff97da7aa591cbd317d91fb5fcb7' + sha: "cb2099c76426ff97da7aa591cbd317d91fb5fcb7", }); }); }); diff --git a/packages/hub/src/lib/dataset-info.ts b/packages/hub/src/lib/dataset-info.ts index bb62df7f8..542b5aa0f 100644 --- a/packages/hub/src/lib/dataset-info.ts +++ b/packages/hub/src/lib/dataset-info.ts @@ -31,7 +31,9 @@ export async function datasetInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/datasets/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/datasets/${params.name}/revision/${encodeURIComponent( + params.revision ?? "HEAD" + )}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), diff --git a/packages/hub/src/lib/download-file-to-cache-dir.spec.ts b/packages/hub/src/lib/download-file-to-cache-dir.spec.ts index 05e2e6de9..879a4d406 100644 --- a/packages/hub/src/lib/download-file-to-cache-dir.spec.ts +++ b/packages/hub/src/lib/download-file-to-cache-dir.spec.ts @@ -8,46 +8,52 @@ import { getHFHubCachePath, getRepoFolderName } from "./cache-management"; import { toRepoId } from "../utils/toRepoId"; import { downloadFileToCacheDir } from "./download-file-to-cache-dir"; -vi.mock('node:fs/promises', () => ({ +vi.mock("node:fs/promises", () => ({ writeFile: vi.fn(), rename: vi.fn(), symlink: vi.fn(), lstat: vi.fn(), mkdir: vi.fn(), - stat: vi.fn() + stat: vi.fn(), })); -vi.mock('./paths-info', () => ({ +vi.mock("./paths-info", () => ({ pathsInfo: vi.fn(), })); const DUMMY_REPO: RepoId = { - name: 'hello-world', - type: 'model', + name: "hello-world", + type: "model", }; const DUMMY_ETAG = "dummy-etag"; // utility test method to get blob file path -function _getBlobFile(params: { +function _getBlobFile(params: { repo: RepoDesignation; etag: string; - cacheDir?: string, // default to {@link getHFHubCache} + cacheDir?: string; // default to {@link getHFHubCache} }) { return join(params.cacheDir ?? getHFHubCachePath(), getRepoFolderName(toRepoId(params.repo)), "blobs", params.etag); } // utility test method to get snapshot file path -function _getSnapshotFile(params: { +function _getSnapshotFile(params: { repo: RepoDesignation; path: string; - revision : string; - cacheDir?: string, // default to {@link getHFHubCache} + revision: string; + cacheDir?: string; // default to {@link getHFHubCache} }) { - return join(params.cacheDir ?? getHFHubCachePath(), getRepoFolderName(toRepoId(params.repo)), "snapshots", params.revision, params.path); + return join( + params.cacheDir ?? getHFHubCachePath(), + getRepoFolderName(toRepoId(params.repo)), + "snapshots", + params.revision, + params.path + ); } -describe('downloadFileToCacheDir', () => { +describe("downloadFileToCacheDir", () => { const fetchMock: typeof fetch = vi.fn(); beforeEach(() => { vi.resetAllMocks(); @@ -55,43 +61,45 @@ describe('downloadFileToCacheDir', () => { vi.mocked(fetchMock).mockResolvedValue({ status: 200, ok: true, - body: 'dummy-body' + body: "dummy-body", } as unknown as Response); // prevent to use caching - vi.mocked(stat).mockRejectedValue(new Error('Do not exists')); - vi.mocked(lstat).mockRejectedValue(new Error('Do not exists')); + vi.mocked(stat).mockRejectedValue(new Error("Do not exists")); + vi.mocked(lstat).mockRejectedValue(new Error("Do not exists")); }); - test('should throw an error if fileDownloadInfo return nothing', async () => { + test("should throw an error if fileDownloadInfo return nothing", async () => { await expect(async () => { await downloadFileToCacheDir({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", fetch: fetchMock, }); - }).rejects.toThrowError('cannot get path info for /README.md'); + }).rejects.toThrowError("cannot get path info for /README.md"); - expect(pathsInfo).toHaveBeenCalledWith(expect.objectContaining({ - repo: DUMMY_REPO, - paths: ['/README.md'], - fetch: fetchMock, - })); + expect(pathsInfo).toHaveBeenCalledWith( + expect.objectContaining({ + repo: DUMMY_REPO, + paths: ["/README.md"], + fetch: fetchMock, + }) + ); }); - test('existing symlinked and blob should not re-download it', async () => { + test("existing symlinked and blob should not re-download it", async () => { // ///snapshots/README.md const expectPointer = _getSnapshotFile({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", }); // stat ensure a symlink and the pointed file exists - vi.mocked(stat).mockResolvedValue({} as Stats) // prevent default mocked reject + vi.mocked(stat).mockResolvedValue({} as Stats); // prevent default mocked reject const output = await downloadFileToCacheDir({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", fetch: fetchMock, revision: "dd4bc8b21efa05ec961e3efc4ee5e3832a3679c7", }); @@ -100,17 +108,17 @@ describe('downloadFileToCacheDir', () => { // Get call argument for stat const starArg = vi.mocked(stat).mock.calls[0][0]; - expect(starArg).toBe(expectPointer) + expect(starArg).toBe(expectPointer); expect(fetchMock).not.toHaveBeenCalledWith(); expect(output).toBe(expectPointer); }); - test('existing blob should only create the symlink', async () => { + test("existing blob should only create the symlink", async () => { // ///snapshots/README.md const expectPointer = _getSnapshotFile({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", revision: "dummy-commit-hash", }); // //blobs/ @@ -122,21 +130,23 @@ describe('downloadFileToCacheDir', () => { // mock existing blob only no symlink vi.mocked(lstat).mockResolvedValue({} as Stats); // mock pathsInfo resolve content - vi.mocked(pathsInfo).mockResolvedValue([{ - oid: DUMMY_ETAG, - size: 55, - path: 'README.md', - type: 'file', - lastCommit: { - date: new Date(), - id: 'dummy-commit-hash', - title: 'Commit msg', + vi.mocked(pathsInfo).mockResolvedValue([ + { + oid: DUMMY_ETAG, + size: 55, + path: "README.md", + type: "file", + lastCommit: { + date: new Date(), + id: "dummy-commit-hash", + title: "Commit msg", + }, }, - }]); + ]); const output = await downloadFileToCacheDir({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", fetch: fetchMock, }); @@ -153,11 +163,11 @@ describe('downloadFileToCacheDir', () => { expect(output).toBe(expectPointer); }); - test('expect resolve value to be the pointer path of downloaded file', async () => { + test("expect resolve value to be the pointer path of downloaded file", async () => { // ///snapshots/README.md const expectPointer = _getSnapshotFile({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", revision: "dummy-commit-hash", }); // //blobs/ @@ -166,21 +176,23 @@ describe('downloadFileToCacheDir', () => { etag: DUMMY_ETAG, }); - vi.mocked(pathsInfo).mockResolvedValue([{ - oid: DUMMY_ETAG, - size: 55, - path: 'README.md', - type: 'file', - lastCommit: { - date: new Date(), - id: 'dummy-commit-hash', - title: 'Commit msg', + vi.mocked(pathsInfo).mockResolvedValue([ + { + oid: DUMMY_ETAG, + size: 55, + path: "README.md", + type: "file", + lastCommit: { + date: new Date(), + id: "dummy-commit-hash", + title: "Commit msg", + }, }, - }]); + ]); const output = await downloadFileToCacheDir({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", fetch: fetchMock, }); @@ -191,11 +203,11 @@ describe('downloadFileToCacheDir', () => { expect(output).toBe(expectPointer); }); - test('should write fetch response to blob', async () => { + test("should write fetch response to blob", async () => { // ///snapshots/README.md const expectPointer = _getSnapshotFile({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", revision: "dummy-commit-hash", }); // //blobs/ @@ -205,30 +217,32 @@ describe('downloadFileToCacheDir', () => { }); // mock pathsInfo resolve content - vi.mocked(pathsInfo).mockResolvedValue([{ - oid: DUMMY_ETAG, - size: 55, - path: 'README.md', - type: 'file', - lastCommit: { - date: new Date(), - id: 'dummy-commit-hash', - title: 'Commit msg', + vi.mocked(pathsInfo).mockResolvedValue([ + { + oid: DUMMY_ETAG, + size: 55, + path: "README.md", + type: "file", + lastCommit: { + date: new Date(), + id: "dummy-commit-hash", + title: "Commit msg", + }, }, - }]); + ]); await downloadFileToCacheDir({ repo: DUMMY_REPO, - path: '/README.md', + path: "/README.md", fetch: fetchMock, }); const incomplete = `${expectedBlob}.incomplete`; // 1. should write fetch#response#body to incomplete file - expect(writeFile).toHaveBeenCalledWith(incomplete, 'dummy-body'); + expect(writeFile).toHaveBeenCalledWith(incomplete, "dummy-body"); // 2. should rename the incomplete to the blob expected name expect(rename).toHaveBeenCalledWith(incomplete, expectedBlob); // 3. should create symlink pointing to blob expect(symlink).toHaveBeenCalledWith(expectedBlob, expectPointer); }); -}); \ No newline at end of file +}); diff --git a/packages/hub/src/lib/download-file-to-cache-dir.ts b/packages/hub/src/lib/download-file-to-cache-dir.ts index 72869f307..92c4edbf0 100644 --- a/packages/hub/src/lib/download-file-to-cache-dir.ts +++ b/packages/hub/src/lib/download-file-to-cache-dir.ts @@ -21,7 +21,7 @@ function getFilePointer(storageFolder: string, revision: string, relativeFilenam */ async function exists(path: string, followSymlinks?: boolean): Promise { try { - if(followSymlinks) { + if (followSymlinks) { await stat(path); } else { await lstat(path); @@ -54,7 +54,7 @@ export async function downloadFileToCacheDir( */ revision?: string; hubUrl?: string; - cacheDir?: string, + cacheDir?: string; /** * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ diff --git a/packages/hub/src/lib/download-file.spec.ts b/packages/hub/src/lib/download-file.spec.ts index f442f152a..01fc64c94 100644 --- a/packages/hub/src/lib/download-file.spec.ts +++ b/packages/hub/src/lib/download-file.spec.ts @@ -3,8 +3,8 @@ import { downloadFile } from "./download-file"; import type { RepoId } from "../types/public"; const DUMMY_REPO: RepoId = { - name: 'hello-world', - type: 'model', + name: "hello-world", + type: "model", }; describe("downloadFile", () => { @@ -17,12 +17,12 @@ describe("downloadFile", () => { await downloadFile({ repo: DUMMY_REPO, - path: '/README.md', - hubUrl: 'http://dummy-hub', + path: "/README.md", + hubUrl: "http://dummy-hub", fetch: fetchMock, }); - expect(fetchMock).toHaveBeenCalledWith('http://dummy-hub/hello-world/resolve/main//README.md', expect.anything()); + expect(fetchMock).toHaveBeenCalledWith("http://dummy-hub/hello-world/resolve/main//README.md", expect.anything()); }); test("raw params should use raw url", async () => { @@ -34,12 +34,12 @@ describe("downloadFile", () => { await downloadFile({ repo: DUMMY_REPO, - path: 'README.md', + path: "README.md", raw: true, fetch: fetchMock, }); - expect(fetchMock).toHaveBeenCalledWith('https://huggingface.co/hello-world/raw/main/README.md', expect.anything()); + expect(fetchMock).toHaveBeenCalledWith("https://huggingface.co/hello-world/raw/main/README.md", expect.anything()); }); test("internal server error should propagate the error", async () => { @@ -49,17 +49,17 @@ describe("downloadFile", () => { ok: false, headers: new Map([["Content-Type", "application/json"]]), json: () => ({ - error: 'Dummy internal error', + error: "Dummy internal error", }), } as unknown as Response); await expect(async () => { await downloadFile({ repo: DUMMY_REPO, - path: 'README.md', + path: "README.md", raw: true, fetch: fetchMock, }); - }).rejects.toThrowError('Dummy internal error'); + }).rejects.toThrowError("Dummy internal error"); }); -}); \ No newline at end of file +}); diff --git a/packages/hub/src/lib/model-info.spec.ts b/packages/hub/src/lib/model-info.spec.ts index 3886f3039..3657e964d 100644 --- a/packages/hub/src/lib/model-info.spec.ts +++ b/packages/hub/src/lib/model-info.spec.ts @@ -21,7 +21,7 @@ describe("modelInfo", () => { }); it("should return the model info with author", async () => { - const info: ModelEntry & Pick = await modelInfo({ + const info: ModelEntry & Pick = await modelInfo({ name: "openai-community/gpt2", additionalFields: ["author"], }); @@ -39,10 +39,10 @@ describe("modelInfo", () => { }); it("should return the model info for a specific revision", async () => { - const info: ModelEntry & Pick = await modelInfo({ + const info: ModelEntry & Pick = await modelInfo({ name: "openai-community/gpt2", additionalFields: ["sha"], - revision: 'f27b190eeac4c2302d24068eabf5e9d6044389ae', + revision: "f27b190eeac4c2302d24068eabf5e9d6044389ae", }); expect(info).toEqual({ id: "621ffdc036468d709f17434d", diff --git a/packages/hub/src/lib/model-info.ts b/packages/hub/src/lib/model-info.ts index 828322e67..4e4291c3b 100644 --- a/packages/hub/src/lib/model-info.ts +++ b/packages/hub/src/lib/model-info.ts @@ -31,7 +31,9 @@ export async function modelInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/models/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/models/${params.name}/revision/${encodeURIComponent( + params.revision ?? "HEAD" + )}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), diff --git a/packages/hub/src/lib/paths-info.spec.ts b/packages/hub/src/lib/paths-info.spec.ts index 994d623ae..837f4a192 100644 --- a/packages/hub/src/lib/paths-info.spec.ts +++ b/packages/hub/src/lib/paths-info.spec.ts @@ -16,8 +16,8 @@ describe("pathsInfo", () => { expect(result).toHaveLength(1); const modelPathInfo = result[0]; - expect(modelPathInfo.path).toBe('tf_model.h5'); - expect(modelPathInfo.type).toBe('file'); + expect(modelPathInfo.path).toBe("tf_model.h5"); + expect(modelPathInfo.type).toBe("file"); // lfs pointer, therefore lfs should be defined expect(modelPathInfo?.lfs).toBeDefined(); expect(modelPathInfo?.lfs?.oid).toBe("a7a17d6d844b5de815ccab5f42cad6d24496db3850a2a43d8258221018ce87d2"); @@ -31,8 +31,8 @@ describe("pathsInfo", () => { it("expand parmas should fetch lastCommit and securityFileStatus", async () => { const result: (PathInfo & { - lastCommit: CommitInfo, - securityFileStatus: SecurityFileStatus, + lastCommit: CommitInfo; + securityFileStatus: SecurityFileStatus; })[] = await pathsInfo({ repo: { name: "bert-base-uncased", @@ -57,7 +57,7 @@ describe("pathsInfo", () => { }); it("non-LFS pointer should have lfs undefined", async () => { - const result: (PathInfo)[] = await pathsInfo({ + const result: PathInfo[] = await pathsInfo({ repo: { name: "bert-base-uncased", type: "model", diff --git a/packages/hub/src/lib/paths-info.ts b/packages/hub/src/lib/paths-info.ts index 4c9a1de20..c706768f1 100644 --- a/packages/hub/src/lib/paths-info.ts +++ b/packages/hub/src/lib/paths-info.ts @@ -5,32 +5,32 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; export interface LfsPathInfo { - "oid": string, - "size": number, - "pointerSize": number + oid: string; + size: number; + pointerSize: number; } -export interface CommitInfo { - "id": string, - "title": string, - "date": Date, +export interface CommitInfo { + id: string; + title: string; + date: Date; } export interface SecurityFileStatus { - "status": string, + status: string; } export interface PathInfo { - path: string, - type: string, - oid: string, - size: number, + path: string; + type: string; + oid: string; + size: number; /** * Only defined when path is LFS pointer */ - lfs?: LfsPathInfo, - lastCommit?: CommitInfo, - securityFileStatus?: SecurityFileStatus + lfs?: LfsPathInfo; + lastCommit?: CommitInfo; + securityFileStatus?: SecurityFileStatus; } // Define the overloaded signatures @@ -45,8 +45,8 @@ export function pathsInfo( * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ fetch?: typeof fetch; - } & Partial -): Promise<(PathInfo & {lastCommit: CommitInfo, securityFileStatus: SecurityFileStatus })[]>; + } & Partial +): Promise<(PathInfo & { lastCommit: CommitInfo; securityFileStatus: SecurityFileStatus })[]>; export function pathsInfo( params: { repo: RepoDesignation; @@ -58,8 +58,8 @@ export function pathsInfo( * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ fetch?: typeof fetch; - } & Partial -): Promise<(PathInfo)[]>; + } & Partial +): Promise; export async function pathsInfo( params: { @@ -72,14 +72,16 @@ export async function pathsInfo( * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ fetch?: typeof fetch; - } & Partial + } & Partial ): Promise { const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); const hubUrl = params.hubUrl ?? HUB_URL; - const url = `${hubUrl}/api/${repoId.type}s/${repoId.name}/paths-info/${encodeURIComponent(params.revision ?? "main")}`; + const url = `${hubUrl}/api/${repoId.type}s/${repoId.name}/paths-info/${encodeURIComponent( + params.revision ?? "main" + )}`; const resp = await (params.fetch ?? fetch)(url, { method: "POST", @@ -87,8 +89,8 @@ export async function pathsInfo( ...(params.credentials && { Authorization: `Bearer ${accessToken}`, }), - 'Accept': 'application/json', - 'Content-Type': 'application/json' + Accept: "application/json", + "Content-Type": "application/json", }, body: JSON.stringify({ paths: params.paths, @@ -101,7 +103,7 @@ export async function pathsInfo( } const json: unknown = await resp.json(); - if(!Array.isArray(json)) throw new Error('malformed response: expected array'); + if (!Array.isArray(json)) throw new Error("malformed response: expected array"); return json.map((item: PathInfo) => ({ path: item.path, @@ -111,10 +113,12 @@ export async function pathsInfo( size: item.size, // expand fields securityFileStatus: item.securityFileStatus, - lastCommit: item.lastCommit ? { - date: new Date(item.lastCommit.date), - title: item.lastCommit.title, - id: item.lastCommit.id, - }: undefined, + lastCommit: item.lastCommit + ? { + date: new Date(item.lastCommit.date), + title: item.lastCommit.title, + id: item.lastCommit.id, + } + : undefined, })); } diff --git a/packages/hub/src/lib/space-info.spec.ts b/packages/hub/src/lib/space-info.spec.ts index aafa9b88f..ea966f98b 100644 --- a/packages/hub/src/lib/space-info.spec.ts +++ b/packages/hub/src/lib/space-info.spec.ts @@ -19,9 +19,9 @@ describe("spaceInfo", () => { }); it("should return the space info with author", async () => { - const info: SpaceEntry & Pick = await spaceInfo({ + const info: SpaceEntry & Pick = await spaceInfo({ name: "huggingfacejs/client-side-oauth", - additionalFields: ['author'], + additionalFields: ["author"], }); expect(info).toEqual({ id: "659835e689010f9c7aed608d", @@ -30,15 +30,15 @@ describe("spaceInfo", () => { likes: expect.any(Number), private: false, sdk: "static", - author: 'huggingfacejs', + author: "huggingfacejs", }); }); it("should return the space info for a given revision", async () => { - const info: SpaceEntry & Pick = await spaceInfo({ + const info: SpaceEntry & Pick = await spaceInfo({ name: "huggingfacejs/client-side-oauth", - additionalFields: ['sha'], - revision: 'e410a9ff348e6bed393b847711e793282d7c672e' + additionalFields: ["sha"], + revision: "e410a9ff348e6bed393b847711e793282d7c672e", }); expect(info).toEqual({ id: "659835e689010f9c7aed608d", @@ -47,7 +47,7 @@ describe("spaceInfo", () => { likes: expect.any(Number), private: false, sdk: "static", - sha: 'e410a9ff348e6bed393b847711e793282d7c672e', + sha: "e410a9ff348e6bed393b847711e793282d7c672e", }); }); }); diff --git a/packages/hub/src/lib/space-info.ts b/packages/hub/src/lib/space-info.ts index fcbfee60d..942235382 100644 --- a/packages/hub/src/lib/space-info.ts +++ b/packages/hub/src/lib/space-info.ts @@ -32,7 +32,9 @@ export async function spaceInfo< ]).toString(); const response = await (params.fetch || fetch)( - `${params?.hubUrl || HUB_URL}/api/spaces/${params.name}/revision/${encodeURIComponent(params.revision ?? "HEAD")}?${search.toString()}`, + `${params?.hubUrl || HUB_URL}/api/spaces/${params.name}/revision/${encodeURIComponent( + params.revision ?? "HEAD" + )}?${search.toString()}`, { headers: { ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), diff --git a/packages/tasks-gen/.prettierignore b/packages/tasks-gen/.prettierignore new file mode 100644 index 000000000..cdbeac2bd --- /dev/null +++ b/packages/tasks-gen/.prettierignore @@ -0,0 +1,5 @@ +dist +snippets-fixtures +node_modules +README.md +pnpm-lock.yaml \ No newline at end of file diff --git a/packages/tasks-gen/README.md b/packages/tasks-gen/README.md index d78e62450..6adbe3211 100644 --- a/packages/tasks-gen/README.md +++ b/packages/tasks-gen/README.md @@ -14,6 +14,7 @@ pnpm generate-snippets-fixtures ``` If some logic has been updated, you should see the result with a + ``` git diff # the diff has to be committed if correct @@ -64,4 +65,3 @@ To update the specs manually, run: ``` pnpm inference-tgi-import ``` - diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bd21daac7..0d2e7bba3 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,6 @@ packages: + - "packages/blob" + - "packages/dduf" - "packages/hub" - "packages/inference" - "packages/doc-internal" From 6dcde5406b0c133ff8dd09fff9e4e838b1aa4ba0 Mon Sep 17 00:00:00 2001 From: machineuser Date: Tue, 3 Dec 2024 13:35:41 +0000 Subject: [PATCH 74/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/blob=200.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/blob/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blob/package.json b/packages/blob/package.json index 26c989be2..0bbdab75d 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/blob", "packageManager": "pnpm@8.10.5", - "version": "0.0.1", + "version": "0.0.2", "description": "Utilities to convert URLs and files to Blobs, internally used by Hugging Face libs", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From c81d4609cce34ad3a6016a915c1c2295c8c54226 Mon Sep 17 00:00:00 2001 From: machineuser Date: Tue, 3 Dec 2024 13:38:59 +0000 Subject: [PATCH 75/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/dduf=200.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/dduf/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dduf/package.json b/packages/dduf/package.json index 61b6330a8..56e1db55c 100644 --- a/packages/dduf/package.json +++ b/packages/dduf/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/dduf", "packageManager": "pnpm@8.10.5", - "version": "0.0.1", + "version": "0.0.2", "description": "Very alpha lib to check DDUF compliance", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 32365c04eda485585e45ba57517cfc3202732455 Mon Sep 17 00:00:00 2001 From: Xuan Son Nguyen Date: Wed, 4 Dec 2024 20:08:10 +0100 Subject: [PATCH 76/97] local-apps: update llama.cpp snippet to use cmake (#1060) Ref: https://github.com/ggerganov/llama.cpp/pull/10514 The recommended way to build llama.cpp is by using `cmake` command. --- packages/tasks/src/local-apps.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/tasks/src/local-apps.ts b/packages/tasks/src/local-apps.ts index 2249183a4..0f2695c13 100644 --- a/packages/tasks/src/local-apps.ts +++ b/packages/tasks/src/local-apps.ts @@ -129,9 +129,10 @@ const snippetLlamacpp = (model: ModelData, filepath?: string): LocalAppSnippet[] setup: [ "git clone https://github.com/ggerganov/llama.cpp.git", "cd llama.cpp", - "LLAMA_CURL=1 make llama-cli", + "cmake -B build -DLLAMA_CURL=ON", + "cmake --build build -j --target llama-cli", ].join("\n"), - content: command("./llama-cli"), + content: command("./build/bin/llama-cli"), }, ]; }; From 690e14315522c2959ea1f2a6b679cd8822afe7ba Mon Sep 17 00:00:00 2001 From: Junsong Chen Date: Thu, 5 Dec 2024 17:37:59 +0800 Subject: [PATCH 77/97] Add Sana .pth files into download counting in huggingface repo (#1061) Co-authored-by: vb Co-authored-by: Lucain Co-authored-by: Lucain --- .../tasks/src/model-libraries-snippets.ts | 20 +++++++++++++++++++ packages/tasks/src/model-libraries.ts | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index 3dc520e0c..91ff1baae 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -982,6 +982,26 @@ IWorker engine = WorkerFactory.CreateWorker(BackendType.GPUCompute, model); `, ]; +export const sana = (model: ModelData): string[] => [ + ` +# Load the model and infer image from text +import torch +from app.sana_pipeline import SanaPipeline +from torchvision.utils import save_image + +sana = SanaPipeline("configs/sana_config/1024ms/Sana_1600M_img1024.yaml") +sana.from_pretrained("hf://${model.id}") + +image = sana( + prompt='a cyberpunk cat with a neon sign that says "Sana"', + height=1024, + width=1024, + guidance_scale=5.0, + pag_guidance_scale=2.0, + num_inference_steps=18, +) `, +]; + export const vfimamba = (model: ModelData): string[] => [ `from Trainer_finetune import Model diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index d8d31a2d4..14f54aef1 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -787,6 +787,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: true, countDownloads: `path_extension:"sentis"`, }, + sana: { + prettyLabel: "Sana", + repoName: "Sana", + repoUrl: "https://github.com/NVlabs/Sana", + countDownloads: `path_extension:"pth"`, + snippets: snippets.sana, + }, "vfi-mamba": { prettyLabel: "VFIMamba", repoName: "VFIMamba", From c32814597522e25507e5115ad2da2ca0301e060a Mon Sep 17 00:00:00 2001 From: machineuser Date: Thu, 5 Dec 2024 09:38:53 +0000 Subject: [PATCH 78/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 4239d6e3e..692f73da6 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.9", + "version": "0.13.10", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 713844ee046fb5652b326529fa0edeeef7dd67a1 Mon Sep 17 00:00:00 2001 From: Sylvain Lesage Date: Thu, 5 Dec 2024 15:11:05 +0100 Subject: [PATCH 79/97] Fix typo in variable name (#1062) --- packages/hub/src/lib/oauth-handle-redirect.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hub/src/lib/oauth-handle-redirect.ts b/packages/hub/src/lib/oauth-handle-redirect.ts index 771b6d439..91e641c52 100644 --- a/packages/hub/src/lib/oauth-handle-redirect.ts +++ b/packages/hub/src/lib/oauth-handle-redirect.ts @@ -100,13 +100,13 @@ export async function oauthHandleRedirect(opts?: { hubUrl?: string }): Promise Date: Thu, 5 Dec 2024 15:34:06 +0100 Subject: [PATCH 80/97] =?UTF-8?q?=F0=9F=92=A5=20Fix=20oauth=20name=20&=20u?= =?UTF-8?q?sername=20mixup=20(#1050)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change format of `userInfo` returned, use raw response from the hub - Make it work in non-browser context (user needs to pass additional args) - useful for automated tests - Add automated tests Due to breaking change, will need major version upgrade In the end I decided to go with the raw response, without transforming it. Because a lot of the fields are standard openID connect fields (eg `preferred_username`), and to make the developer's job easier when they search docs or they already have other OpenID integrations in their app. Even if it's snake_case while the rest of the API is camelCase. --- packages/hub/src/error.ts | 3 + packages/hub/src/lib/create-repo.ts | 3 + .../hub/src/lib/oauth-handle-redirect.spec.ts | 60 +++++ packages/hub/src/lib/oauth-handle-redirect.ts | 245 +++++++++++++----- packages/hub/src/lib/oauth-login-url.ts | 50 +++- packages/hub/src/test/consts.ts | 1 + packages/hub/vitest-browser.config.mts | 2 + 7 files changed, 284 insertions(+), 80 deletions(-) create mode 100644 packages/hub/src/lib/oauth-handle-redirect.spec.ts diff --git a/packages/hub/src/error.ts b/packages/hub/src/error.ts index f0a3e33c4..0da5b2dd9 100644 --- a/packages/hub/src/error.ts +++ b/packages/hub/src/error.ts @@ -15,6 +15,9 @@ export async function createApiError( if (response.headers.get("Content-Type")?.startsWith("application/json")) { const json = await response.json(); error.message = json.error || json.message || error.message; + if (json.error_description) { + error.message = error.message ? error.message + `: ${json.error_description}` : json.error_description; + } error.data = json; } else { error.data = { message: await response.text() }; diff --git a/packages/hub/src/lib/create-repo.ts b/packages/hub/src/lib/create-repo.ts index 4005844d6..c0323dc11 100644 --- a/packages/hub/src/lib/create-repo.ts +++ b/packages/hub/src/lib/create-repo.ts @@ -9,6 +9,9 @@ import { toRepoId } from "../utils/toRepoId"; export async function createRepo( params: { repo: RepoDesignation; + /** + * If unset, will follow the organization's default setting. (typically public, except for some Enterprise organizations) + */ private?: boolean; license?: string; /** diff --git a/packages/hub/src/lib/oauth-handle-redirect.spec.ts b/packages/hub/src/lib/oauth-handle-redirect.spec.ts new file mode 100644 index 000000000..f06f6a40e --- /dev/null +++ b/packages/hub/src/lib/oauth-handle-redirect.spec.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from "vitest"; +import { TEST_COOKIE, TEST_HUB_URL } from "../test/consts"; +import { oauthLoginUrl } from "./oauth-login-url"; +import { oauthHandleRedirect } from "./oauth-handle-redirect"; + +describe("oauthHandleRedirect", () => { + it("should work", async () => { + const localStorage = { + nonce: undefined, + codeVerifier: undefined, + }; + const url = await oauthLoginUrl({ + clientId: "dummy-app", + redirectUrl: "http://localhost:3000", + localStorage, + scopes: "openid profile email", + hubUrl: TEST_HUB_URL, + }); + const resp = await fetch(url, { + method: "POST", + headers: { + Cookie: `token=${TEST_COOKIE}`, + }, + redirect: "manual", + }); + if (resp.status !== 303) { + throw new Error(`Failed to fetch url ${url}: ${resp.status} ${resp.statusText}`); + } + const location = resp.headers.get("Location"); + if (!location) { + throw new Error(`No location header in response`); + } + const result = await oauthHandleRedirect({ + redirectedUrl: location, + codeVerifier: localStorage.codeVerifier, + nonce: localStorage.nonce, + hubUrl: TEST_HUB_URL, + }); + + if (!result) { + throw new Error("Expected result to be defined"); + } + expect(result.accessToken).toEqual(expect.any(String)); + expect(result.accessTokenExpiresAt).toBeInstanceOf(Date); + expect(result.accessTokenExpiresAt.getTime()).toBeGreaterThan(Date.now()); + expect(result.scope).toEqual(expect.any(String)); + expect(result.userInfo).toEqual({ + sub: "62f264b9f3c90f4b6514a269", + name: "@huggingface/hub CI bot", + preferred_username: "hub.js", + email_verified: true, + email: "eliott@huggingface.co", + isPro: false, + picture: "https://hub-ci.huggingface.co/avatars/934b830e9fdaa879487852f79eef7165.svg", + profile: "https://hub-ci.huggingface.co/hub.js", + website: "https://github.com/huggingface/hub.js", + orgs: [], + }); + }); +}); diff --git a/packages/hub/src/lib/oauth-handle-redirect.ts b/packages/hub/src/lib/oauth-handle-redirect.ts index 91e641c52..4df6311ec 100644 --- a/packages/hub/src/lib/oauth-handle-redirect.ts +++ b/packages/hub/src/lib/oauth-handle-redirect.ts @@ -1,28 +1,100 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; +export interface UserInfo { + /** + * OpenID Connect field. Unique identifier for the user, even in case of rename. + */ + sub: string; + /** + * OpenID Connect field. The user's full name. + */ + name: string; + /** + * OpenID Connect field. The user's username. + */ + preferred_username: string; + /** + * OpenID Connect field, available if scope "email" was granted. + */ + email_verified?: boolean; + /** + * OpenID Connect field, available if scope "email" was granted. + */ + email?: string; + /** + * OpenID Connect field. The user's profile picture URL. + */ + picture: string; + /** + * OpenID Connect field. The user's profile URL. + */ + profile: string; + /** + * OpenID Connect field. The user's website URL. + */ + website?: string; + + /** + * Hugging Face field. Whether the user is a pro user. + */ + isPro: boolean; + /** + * Hugging Face field. Whether the user has a payment method set up. Needs "read-billing" scope. + */ + canPay?: boolean; + /** + * Hugging Face field. The user's orgs + */ + orgs?: Array<{ + /** + * OpenID Connect field. Unique identifier for the org. + */ + sub: string; + /** + * OpenID Connect field. The org's full name. + */ + name: string; + /** + * OpenID Connect field. The org's username. + */ + preferred_username: string; + /** + * OpenID Connect field. The org's profile picture URL. + */ + picture: string; + + /** + * Hugging Face field. Whether the org is an enterprise org. + */ + isEnterprise: boolean; + /** + * Hugging Face field. Whether the org has a payment method set up. Needs "read-billing" scope, and the user needs to approve access to the org in the OAuth page. + */ + canPay?: boolean; + /** + * Hugging Face field. The user's role in the org. The user needs to approve access to the org in the OAuth page. + */ + roleInOrg?: string; + /** + * HuggingFace field. When the user granted the oauth app access to the org, but didn't complete SSO. + * + * Should never happen directly after the oauth flow. + */ + pendingSSO?: boolean; + /** + * HuggingFace field. When the user granted the oauth app access to the org, but didn't complete MFA. + * + * Should never happen directly after the oauth flow. + */ + missingMFA?: boolean; + }>; +} + export interface OAuthResult { accessToken: string; accessTokenExpiresAt: Date; - userInfo: { - id: string; - name: string; - fullname: string; - email?: string; - emailVerified?: boolean; - avatarUrl: string; - websiteUrl?: string; - isPro: boolean; - canPay?: boolean; - orgs: Array<{ - id: string; - name: string; - isEnterprise: boolean; - canPay?: boolean; - avatarUrl: string; - roleInOrg?: string; - }>; - }; + userInfo: UserInfo; /** * State passed to the OAuth provider in the original request to the OAuth provider. */ @@ -39,12 +111,47 @@ export interface OAuthResult { * There is also a helper function {@link oauthHandleRedirectIfPresent}, which will call `oauthHandleRedirect` if the URL contains an oauth code * in the query parameters and return `false` otherwise. */ -export async function oauthHandleRedirect(opts?: { hubUrl?: string }): Promise { - if (typeof window === "undefined") { - throw new Error("oauthHandleRedirect is only available in the browser"); +export async function oauthHandleRedirect(opts?: { + /** + * The URL of the hub. Defaults to {@link HUB_URL}. + */ + hubUrl?: string; + /** + * The URL to analyze. + * + * @default window.location.href + */ + redirectedUrl?: string; + /** + * nonce generated by oauthLoginUrl + * + * @default localStorage.getItem("huggingface.co:oauth:nonce") + */ + nonce?: string; + /** + * codeVerifier generated by oauthLoginUrl + * + * @default localStorage.getItem("huggingface.co:oauth:code_verifier") + */ + codeVerifier?: string; +}): Promise { + if (typeof window === "undefined" && !opts?.redirectedUrl) { + throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl"); + } + if (typeof localStorage === "undefined" && (!opts?.nonce || !opts?.codeVerifier)) { + throw new Error( + "oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier" + ); } - const searchParams = new URLSearchParams(window.location.search); + const redirectedUrl = opts?.redirectedUrl ?? window.location.href; + const searchParams = (() => { + try { + return new URL(redirectedUrl).searchParams; + } catch (err) { + throw new Error("Failed to parse redirected URL: " + redirectedUrl); + } + })(); const [error, errorDescription] = [searchParams.get("error"), searchParams.get("error_description")]; @@ -53,17 +160,17 @@ export async function oauthHandleRedirect(opts?: { hubUrl?: string }): Promise; - } = await userInfoRes.json(); + const userInfo: UserInfo = await userInfoRes.json(); return { accessToken: token.access_token, accessTokenExpiresAt, - userInfo: { - id: userInfo.sub, - name: userInfo.name, - fullname: userInfo.preferred_username, - email: userInfo.email, - emailVerified: userInfo.email_verified, - avatarUrl: userInfo.picture, - websiteUrl: userInfo.website, - isPro: userInfo.isPro, - orgs: - userInfo.orgs?.map((org) => ({ - id: org.sub, - name: org.name, - fullname: org.name, - isEnterprise: org.isEnterprise, - canPay: org.canPay, - avatarUrl: org.picture, - roleInOrg: org.roleInOrg, - })) ?? [], - }, + userInfo: userInfo, state: parsedState.state, scope: token.scope, }; @@ -207,12 +281,39 @@ export async function oauthHandleRedirect(opts?: { hubUrl?: string }): Promise { - if (typeof window === "undefined") { - throw new Error("oauthHandleRedirect is only available in the browser"); +export async function oauthHandleRedirectIfPresent(opts?: { + /** + * The URL of the hub. Defaults to {@link HUB_URL}. + */ + hubUrl?: string; + /** + * The URL to analyze. + * + * @default window.location.href + */ + redirectedUrl?: string; + /** + * nonce generated by oauthLoginUrl + * + * @default localStorage.getItem("huggingface.co:oauth:nonce") + */ + nonce?: string; + /** + * codeVerifier generated by oauthLoginUrl + * + * @default localStorage.getItem("huggingface.co:oauth:code_verifier") + */ + codeVerifier?: string; +}): Promise { + if (typeof window === "undefined" && !opts?.redirectedUrl) { + throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl"); } - - const searchParams = new URLSearchParams(window.location.search); + if (typeof localStorage === "undefined" && (!opts?.nonce || !opts?.codeVerifier)) { + throw new Error( + "oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier" + ); + } + const searchParams = new URLSearchParams(opts?.redirectedUrl ?? window.location.search); if (searchParams.has("error")) { return oauthHandleRedirect(opts); diff --git a/packages/hub/src/lib/oauth-login-url.ts b/packages/hub/src/lib/oauth-login-url.ts index 9067ba994..9b8bca3f3 100644 --- a/packages/hub/src/lib/oauth-login-url.ts +++ b/packages/hub/src/lib/oauth-login-url.ts @@ -40,7 +40,7 @@ export async function oauthLoginUrl(opts?: { clientId?: string; hubUrl?: string; /** - * OAuth scope, a list of space separate scopes. + * OAuth scope, a list of space-separated scopes. * * For static Spaces, you can omit this and it will be loaded from the Space config, as long as `hf_oauth: true` is present in the README.md's metadata. * For other Spaces, it is available to the backend in the OAUTH_SCOPES environment variable, as long as `hf_oauth: true` is present in the README.md's metadata. @@ -64,9 +64,24 @@ export async function oauthLoginUrl(opts?: { * State to pass to the OAuth provider, which will be returned in the call to `oauthLogin` after the redirect. */ state?: string; + /** + * If provided, will be filled with the code verifier and nonce used for the OAuth flow, + * instead of using localStorage. + * + * When calling {@link `oauthHandleRedirectIfPresent`} or {@link `oauthHandleRedirect`} you will need to provide the same values. + */ + localStorage?: { + codeVerifier?: string; + nonce?: string; + }; }): Promise { - if (typeof window === "undefined") { - throw new Error("oauthLogin is only available in the browser"); + if (typeof window === "undefined" && (!opts?.redirectUrl || !opts?.clientId)) { + throw new Error("oauthLogin is only available in the browser, unless you provide clientId and redirectUrl"); + } + if (typeof localStorage === "undefined" && !opts?.localStorage) { + throw new Error( + "oauthLogin requires localStorage to be available in the context, unless you provide a localStorage empty object as argument" + ); } const hubUrl = opts?.hubUrl || HUB_URL; @@ -91,18 +106,37 @@ export async function oauthLoginUrl(opts?: { // Two random UUIDs concatenated together, because min length is 43 and max length is 128 const newCodeVerifier = globalThis.crypto.randomUUID() + globalThis.crypto.randomUUID(); - localStorage.setItem("huggingface.co:oauth:nonce", newNonce); - localStorage.setItem("huggingface.co:oauth:code_verifier", newCodeVerifier); + if (opts?.localStorage) { + if (opts.localStorage.codeVerifier !== undefined && opts.localStorage.codeVerifier !== null) { + throw new Error( + "localStorage.codeVerifier must be a initially set to null or undefined, and will be filled by oauthLoginUrl" + ); + } + if (opts.localStorage.nonce !== undefined && opts.localStorage.nonce !== null) { + throw new Error( + "localStorage.nonce must be a initially set to null or undefined, and will be filled by oauthLoginUrl" + ); + } + opts.localStorage.codeVerifier = newCodeVerifier; + opts.localStorage.nonce = newNonce; + } else { + localStorage.setItem("huggingface.co:oauth:nonce", newNonce); + localStorage.setItem("huggingface.co:oauth:code_verifier", newCodeVerifier); + } - const redirectUri = opts?.redirectUrl || window.location.href; + const redirectUri = opts?.redirectUrl || (typeof window !== "undefined" ? window.location.href : undefined); + if (!redirectUri) { + throw new Error("Missing redirectUrl"); + } const state = JSON.stringify({ nonce: newNonce, redirectUri, state: opts?.state, }); - // @ts-expect-error window.huggingface is defined inside static Spaces. - const variables: Record | null = window?.huggingface?.variables ?? null; + const variables: Record | null = + // @ts-expect-error window.huggingface is defined inside static Spaces. + typeof window !== "undefined" ? window.huggingface?.variables ?? null : null; const clientId = opts?.clientId || variables?.OAUTH_CLIENT_ID; diff --git a/packages/hub/src/test/consts.ts b/packages/hub/src/test/consts.ts index 297ea01d0..6b8b7983d 100644 --- a/packages/hub/src/test/consts.ts +++ b/packages/hub/src/test/consts.ts @@ -1,3 +1,4 @@ export const TEST_HUB_URL = "https://hub-ci.huggingface.co"; export const TEST_USER = "hub.js"; export const TEST_ACCESS_TOKEN = "hf_hub.js"; +export const TEST_COOKIE = "huggingface-hub.js-cookie"; diff --git a/packages/hub/vitest-browser.config.mts b/packages/hub/vitest-browser.config.mts index db22fb67c..2c21588af 100644 --- a/packages/hub/vitest-browser.config.mts +++ b/packages/hub/vitest-browser.config.mts @@ -8,6 +8,8 @@ export default defineConfig({ "src/lib/cache-management.spec.ts", "src/lib/download-file-to-cache-dir.spec.ts", "src/lib/snapshot-download.spec.ts", + // Because we use redirect: "manual" in the test + "src/lib/oauth-handle-redirect.spec.ts", ], }, }); From 2b4643f11775be24edc2564d36219b428a8fd972 Mon Sep 17 00:00:00 2001 From: Sylvain Lesage Date: Thu, 5 Dec 2024 15:41:11 +0100 Subject: [PATCH 81/97] use accessToken in listDatasets (#1064) fix #1063 --- packages/hub/src/lib/file-download-info.ts | 2 +- packages/hub/src/lib/list-datasets.ts | 2 +- packages/hub/src/lib/list-models.ts | 2 +- packages/hub/src/lib/list-spaces.ts | 2 +- packages/hub/src/lib/paths-info.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/hub/src/lib/file-download-info.ts b/packages/hub/src/lib/file-download-info.ts index 210bd11e7..3dcc79ee9 100644 --- a/packages/hub/src/lib/file-download-info.ts +++ b/packages/hub/src/lib/file-download-info.ts @@ -50,7 +50,7 @@ export async function fileDownloadInfo( const resp = await (params.fetch ?? fetch)(url, { method: "GET", headers: { - ...(params.credentials && { + ...(accessToken && { Authorization: `Bearer ${accessToken}`, }), Range: "bytes=0-0", diff --git a/packages/hub/src/lib/list-datasets.ts b/packages/hub/src/lib/list-datasets.ts index 5bfbc4a15..fecfa8c32 100644 --- a/packages/hub/src/lib/list-datasets.ts +++ b/packages/hub/src/lib/list-datasets.ts @@ -86,7 +86,7 @@ export async function* listDatasets< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), + ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/list-models.ts b/packages/hub/src/lib/list-models.ts index 0e62c8caf..db241c458 100644 --- a/packages/hub/src/lib/list-models.ts +++ b/packages/hub/src/lib/list-models.ts @@ -94,7 +94,7 @@ export async function* listModels< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), + ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/list-spaces.ts b/packages/hub/src/lib/list-spaces.ts index 36a251afd..a14e7e301 100644 --- a/packages/hub/src/lib/list-spaces.ts +++ b/packages/hub/src/lib/list-spaces.ts @@ -82,7 +82,7 @@ export async function* listSpaces< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), + ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/paths-info.ts b/packages/hub/src/lib/paths-info.ts index c706768f1..ec455f882 100644 --- a/packages/hub/src/lib/paths-info.ts +++ b/packages/hub/src/lib/paths-info.ts @@ -86,7 +86,7 @@ export async function pathsInfo( const resp = await (params.fetch ?? fetch)(url, { method: "POST", headers: { - ...(params.credentials && { + ...(accessToken && { Authorization: `Bearer ${accessToken}`, }), Accept: "application/json", From 53261b2351c7ccc93e5c4074d201f84dddad1081 Mon Sep 17 00:00:00 2001 From: machineuser Date: Fri, 6 Dec 2024 13:15:52 +0000 Subject: [PATCH 82/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/hub=201.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- packages/hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4fb9b797f..838f80045 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or ```html ``` diff --git a/packages/hub/package.json b/packages/hub/package.json index 9e84de2c1..c9a21f096 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/hub", "packageManager": "pnpm@8.10.5", - "version": "0.21.0", + "version": "1.0.0", "description": "Utilities to interact with the Hugging Face hub", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 3fb4cfba86fc18bd818cbfffa2cc4a9783f48323 Mon Sep 17 00:00:00 2001 From: Ofer Hasson Date: Fri, 6 Dec 2024 17:25:42 +0200 Subject: [PATCH 83/97] Add Birder as a library to model-libraries.ts (#1066) Allow correct download stats. --- packages/tasks/src/model-libraries.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 14f54aef1..262d4b8cd 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -114,6 +114,13 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { filter: false, countDownloads: `path_extension:"npz"`, }, + birder: { + prettyLabel: "Birder", + repoName: "Birder", + repoUrl: "https://gitlab.com/birder/birder", + filter: false, + countDownloads: `path_extension:"pt"`, + }, birefnet: { prettyLabel: "BiRefNet", repoName: "BiRefNet", From 930eebd09dcf06e335b0f2b8c7066523f6f07279 Mon Sep 17 00:00:00 2001 From: Harrison Cook Date: Fri, 6 Dec 2024 18:51:02 +0100 Subject: [PATCH 84/97] Add AnemoI to model-libraries.ts (#1067) # Add AnemoI https://anemoi-training.readthedocs.io/en/latest/ ECMWF is building a toolkit to enable development of ML weather models. Support will be added for the huggingface hub within the anemoi inference repo. --------- Co-authored-by: Lucain Co-authored-by: Lucain --- packages/tasks/src/model-libraries-snippets.ts | 5 +++++ packages/tasks/src/model-libraries.ts | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index 91ff1baae..f9553860d 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -1118,6 +1118,11 @@ model.set_generation_params(duration=5) # generate 5 seconds. descriptions = ['dog barking', 'sirene of an emergency vehicle', 'footsteps in a corridor'] wav = model.generate(descriptions) # generates 3 samples.`, ]; +export const anemoi = (model: ModelData): string[] => [ + `from anemoi.inference.runners import DefaultRunner + runner = DefaultRunner("${model.id}")`, +]; + export const audiocraft = (model: ModelData): string[] => { if (model.tags.includes("musicgen")) { diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 262d4b8cd..8cc1fe197 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -75,6 +75,15 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { snippets: snippets.allennlp, filter: true, }, + anemoi: { + prettyLabel: "AnemoI", + repoName: "AnemoI", + repoUrl: "https://github.com/ecmwf/anemoi-inference", + docsUrl: "https://anemoi-docs.readthedocs.io/en/latest/", + filter: false, + countDownloads: `path_extension:"ckpt"`, + snippets: snippets.anemoi, + }, asteroid: { prettyLabel: "Asteroid", repoName: "Asteroid", From bebee8f3f1977d2d81b966f5aaf189fac39624c2 Mon Sep 17 00:00:00 2001 From: machineuser Date: Fri, 6 Dec 2024 17:52:47 +0000 Subject: [PATCH 85/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 692f73da6..2bc555fb2 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.10", + "version": "0.13.11", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From fd95e172244a85b1736e48e2a297b524d87e3c79 Mon Sep 17 00:00:00 2001 From: NielsRogge <48327001+NielsRogge@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:26:16 +0100 Subject: [PATCH 86/97] Add Trellis as a library (#1068) This PR enables download counts for trellis: https://huggingface.co/JeffreyXiang/TRELLIS-image-large. Related PR: https://github.com/microsoft/TRELLIS/issues/9 --------- Co-authored-by: Lucain --- packages/tasks/src/model-libraries.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 8cc1fe197..4b8a65553 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -795,6 +795,12 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { snippets: snippets.transformersJS, filter: true, }, + "trellis": { + prettyLabel: "Trellis", + repoName: "Trellis", + repoUrl: "https://github.com/microsoft/TRELLIS", + countDownloads: `path_extension:"safetensors"`, + }, "unity-sentis": { prettyLabel: "unity-sentis", repoName: "unity-sentis", From 30ec651768573c0cccc89dfa1a8157a51f2f80dc Mon Sep 17 00:00:00 2001 From: HuggingFaceInfra <148469759+HuggingFaceInfra@users.noreply.github.com> Date: Mon, 9 Dec 2024 08:15:43 +0100 Subject: [PATCH 87/97] [Bot] Update tasks specs (#1069) This PR updates the @huggingface/tasks specs. It has been generated by running: ```sh pnpm run inference-tgi-import pnpm run inference-tei-import pnpm run inference-codegen ``` This PR was automatically created by the [Tasks - Update specs workflow](https://github.com/huggingface/huggingface.js/blob/main/.github/update-specs.yml). Make sure the changes are correct before merging. Co-authored-by: Wauplin <11801849+Wauplin@users.noreply.github.com> --- packages/tasks/src/tasks/chat-completion/spec/input.json | 1 + packages/tasks/src/tasks/text-generation/spec/input.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tasks/src/tasks/chat-completion/spec/input.json b/packages/tasks/src/tasks/chat-completion/spec/input.json index b34de9953..a4a9ab5fe 100644 --- a/packages/tasks/src/tasks/chat-completion/spec/input.json +++ b/packages/tasks/src/tasks/chat-completion/spec/input.json @@ -32,6 +32,7 @@ "type": "integer", "format": "int32", "description": "The maximum number of tokens that can be generated in the chat completion.", + "default": "1024", "example": "32", "nullable": true, "minimum": 0 diff --git a/packages/tasks/src/tasks/text-generation/spec/input.json b/packages/tasks/src/tasks/text-generation/spec/input.json index 108d9fb3c..0d160419a 100644 --- a/packages/tasks/src/tasks/text-generation/spec/input.json +++ b/packages/tasks/src/tasks/text-generation/spec/input.json @@ -76,7 +76,7 @@ "type": "integer", "format": "int32", "description": "Maximum number of tokens to generate.", - "default": "100", + "default": "1024", "example": "20", "nullable": true, "minimum": 0 From 8776c8ac900195da2b8174201c81dba6cee9c093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Mu=C5=A1tar?= Date: Mon, 9 Dec 2024 17:34:36 +0100 Subject: [PATCH 88/97] Update default-widget-inputs.ts (#1070) --- packages/tasks/src/default-widget-inputs.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/tasks/src/default-widget-inputs.ts b/packages/tasks/src/default-widget-inputs.ts index 906a0dcc0..220911e69 100644 --- a/packages/tasks/src/default-widget-inputs.ts +++ b/packages/tasks/src/default-widget-inputs.ts @@ -69,7 +69,7 @@ const MAPPING_EN: PerLanguageMapping = new Map([ "zero-shot-classification", [ { - text: "I have a problem with my iphone that needs to be resolved asap!!", + text: "I have a problem with my iphone that needs to be resolved asap!", candidate_labels: "urgent, not urgent, phone, tablet, computer", multi_class: true, }, @@ -95,24 +95,18 @@ const MAPPING_EN: PerLanguageMapping = new Map([ [ "conversational", [ - `Hey my name is Julien! How are you?`, - `Hey my name is Thomas! How are you?`, - `Hey my name is Mariama! How are you?`, + `Hi, what can you help me with?`, + `Hey, let's have a conversation!`, + `Hello there!`, `Hey my name is Clara! How are you?`, - `Hey my name is Julien! How are you?`, - `Hi.`, ], ], [ "text-generation", [ `My name is Julien and I like to`, - `My name is Thomas and my main`, - `My name is Mariama, my favorite`, - `My name is Clara and I am`, - `My name is Lewis and I like to`, - `My name is Merve and my favorite`, - `My name is Teven and I am`, + `I like traveling by train because`, + `Paris is an amazing place to visit,`, `Once upon a time,`, ], ], From c0b2ca3720a2f8bbeb48a055737884c3fa043f7a Mon Sep 17 00:00:00 2001 From: machineuser Date: Tue, 10 Dec 2024 09:42:26 +0000 Subject: [PATCH 89/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index 2bc555fb2..e5f979b99 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.11", + "version": "0.13.12", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 6ff6584309ef71af509d441d044e890a44aa01c8 Mon Sep 17 00:00:00 2001 From: Harrison Cook Date: Thu, 12 Dec 2024 08:05:49 +0000 Subject: [PATCH 90/97] Rework anemoi snippet (#1071) # Rework anemoi snippet - Fix snippet to allow for easy instantiation See https://github.com/ecmwf/anemoi-inference/pull/77 ```python from anemoi.inference.runners.default import DefaultRunner from anemoi.inference.config import Configuration # Create Configuration config = Configuration(checkpoint = {"huggingface":{"repo_id":"ecwmf/aifs-single"}}) # Load Runner runner = DefaultRunner(config) ``` --- packages/tasks/src/model-libraries-snippets.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index f9553860d..2935d777b 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -1119,8 +1119,12 @@ descriptions = ['dog barking', 'sirene of an emergency vehicle', 'footsteps in a wav = model.generate(descriptions) # generates 3 samples.`, ]; export const anemoi = (model: ModelData): string[] => [ - `from anemoi.inference.runners import DefaultRunner - runner = DefaultRunner("${model.id}")`, + `from anemoi.inference.runners.default import DefaultRunner +from anemoi.inference.config import Configuration +# Create Configuration +config = Configuration(checkpoint = {"huggingface":{"repo_id":"${model.id}"}}) +# Load Runner +runner = DefaultRunner(config)`, ]; From d01296c37804da22c55e5a6e1af3a1cf4f8bc59c Mon Sep 17 00:00:00 2001 From: machineuser Date: Thu, 12 Dec 2024 08:06:53 +0000 Subject: [PATCH 91/97] =?UTF-8?q?=F0=9F=94=96=20@huggingface/tasks=200.13.?= =?UTF-8?q?13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/tasks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/package.json b/packages/tasks/package.json index e5f979b99..78bf63d21 100644 --- a/packages/tasks/package.json +++ b/packages/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@huggingface/tasks", "packageManager": "pnpm@8.10.5", - "version": "0.13.12", + "version": "0.13.13", "description": "List of ML tasks for huggingface.co/tasks", "repository": "https://github.com/huggingface/huggingface.js.git", "publishConfig": { From 8c62f4ae96e27caaf6e116adc8a04ad4df68e751 Mon Sep 17 00:00:00 2001 From: Merve Noyan Date: Thu, 12 Dec 2024 17:50:31 +0100 Subject: [PATCH 92/97] Tasks: Add image-text-to-text pipeline and inference API to task page (#1039) ..and remove the long inference --------- Co-authored-by: Pedro Cuenca Co-authored-by: vb Co-authored-by: Merve Noyan --- .../src/tasks/image-text-to-text/about.md | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/tasks/src/tasks/image-text-to-text/about.md b/packages/tasks/src/tasks/image-text-to-text/about.md index f220604fc..8da1621bb 100644 --- a/packages/tasks/src/tasks/image-text-to-text/about.md +++ b/packages/tasks/src/tasks/image-text-to-text/about.md @@ -32,39 +32,51 @@ Vision language models can recognize images through descriptions. When given det ## Inference -You can use the Transformers library to interact with vision-language models. You can load the model like below. +You can use the Transformers library to interact with [vision-language models](https://huggingface.co/models?pipeline_tag=image-text-to-text&transformers). Specifically, `pipeline` makes it easy to infer models. + +Initialize the pipeline first. + +```python +from transformers import pipeline + +pipe = pipeline("image-text-to-text", model="llava-hf/llava-interleave-qwen-0.5b-hf") +``` + +The model's built-in chat template will be used to format the conversational input. We can pass the image as an URL in the `content` part of the user message: ```python -from transformers import LlavaNextProcessor, LlavaNextForConditionalGeneration -import torch - -device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') -processor = LlavaNextProcessor.from_pretrained("llava-hf/llava-v1.6-mistral-7b-hf") -model = LlavaNextForConditionalGeneration.from_pretrained( - "llava-hf/llava-v1.6-mistral-7b-hf", - torch_dtype=torch.float16 -) -model.to(device) +messages = [ + { + "role": "user", + "content": [ + { + "type": "image", + "image": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg", + }, + {"type": "text", "text": "Describe this image."}, + ], + } + ] + ``` -We can infer by passing image and text dialogues. +We can now directly pass in the messages to the pipeline to infer. The `return_full_text` flag is used to return the full prompt in the response, including the user input. Here we pass `False` to only return the generated text. ```python -from PIL import Image -import requests +outputs = pipe(text=messages, max_new_tokens=60, return_full_text=False) -# image of a radar chart -url = "https://github.com/haotian-liu/LLaVA/blob/1a91fc274d7c35a9b50b3cb29c4247ae5837ce39/images/llava_v1_5_radar.jpg?raw=true" -image = Image.open(requests.get(url, stream=True).raw) -prompt = "[INST] \nWhat is shown in this image? [/INST]" +outputs[0]["generated_text"] +# The image captures a moment of tranquility in nature. At the center of the frame, a pink flower with a yellow center is in full bloom. The flower is surrounded by a cluster of red flowers, their vibrant color contrasting with the pink of the flower. \n\nA black and yellow bee is per +``` -inputs = processor(prompt, image, return_tensors="pt").to(device) -output = model.generate(**inputs, max_new_tokens=100) +You can also use the Inference API to test image-text-to-text models. You need to use a [Hugging Face token](https://huggingface.co/settings/tokens) for authentication. -print(processor.decode(output[0], skip_special_tokens=True)) -# The image appears to be a radar chart, which is a type of multivariate chart that displays values for multiple variables represented on axes -# starting from the same point. This particular radar chart is showing the performance of different models or systems across various metrics. -# The axes represent different metrics or benchmarks, such as MM-Vet, MM-Vet, MM-Vet, MM-Vet, MM-Vet, MM-V +```bash +curl https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct \ + -X POST \ + -d '{"messages": [{"role": "user","content": [{"type": "image"}, {"type": "text", "text": "Can you describe the image?"}]}]}' \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer hf_***" ``` ## Useful Resources From 0a280ca9c86c3a2bf83d222520e7021f53f46b77 Mon Sep 17 00:00:00 2001 From: Haoxian WANG Date: Sat, 14 Dec 2024 17:16:48 +0100 Subject: [PATCH 93/97] Update hardware.ts - Add RTX A2000 to specs (#1074) Hello, I would like to add this GPU that I am using. Many thanks. Cc: @Vaibhavs10 GPU info: - https://www.techpowerup.com/gpu-specs/rtx-a2000.c3820 - https://www.techpowerup.com/gpu-specs/rtx-a2000-12-gb.c3853 --- packages/tasks/src/hardware.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/tasks/src/hardware.ts b/packages/tasks/src/hardware.ts index efde8177b..ae60bd4e7 100644 --- a/packages/tasks/src/hardware.ts +++ b/packages/tasks/src/hardware.ts @@ -76,6 +76,10 @@ export const SKUS = { tflops: 19.2, memory: [16], }, + "RTX A2000": { + tflops: 7.987, + memory: [8, 12] + }, A100: { tflops: 77.97, memory: [80, 40], From 5e30578ff8dc4870da7a6454bbd3d5063a794a24 Mon Sep 17 00:00:00 2001 From: Pedro Cuenca Date: Mon, 16 Dec 2024 12:44:51 +0100 Subject: [PATCH 94/97] Fix linter (#1075) --- packages/tasks/src/hardware.ts | 2 +- packages/tasks/src/model-libraries-snippets.ts | 1 - packages/tasks/src/model-libraries.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/tasks/src/hardware.ts b/packages/tasks/src/hardware.ts index ae60bd4e7..9999b0aec 100644 --- a/packages/tasks/src/hardware.ts +++ b/packages/tasks/src/hardware.ts @@ -78,7 +78,7 @@ export const SKUS = { }, "RTX A2000": { tflops: 7.987, - memory: [8, 12] + memory: [8, 12], }, A100: { tflops: 77.97, diff --git a/packages/tasks/src/model-libraries-snippets.ts b/packages/tasks/src/model-libraries-snippets.ts index 2935d777b..b0c2ae421 100644 --- a/packages/tasks/src/model-libraries-snippets.ts +++ b/packages/tasks/src/model-libraries-snippets.ts @@ -1127,7 +1127,6 @@ config = Configuration(checkpoint = {"huggingface":{"repo_id":"${model.id}"}}) runner = DefaultRunner(config)`, ]; - export const audiocraft = (model: ModelData): string[] => { if (model.tags.includes("musicgen")) { return musicgen(model); diff --git a/packages/tasks/src/model-libraries.ts b/packages/tasks/src/model-libraries.ts index 4b8a65553..5eedfdfed 100644 --- a/packages/tasks/src/model-libraries.ts +++ b/packages/tasks/src/model-libraries.ts @@ -795,7 +795,7 @@ export const MODEL_LIBRARIES_UI_ELEMENTS = { snippets: snippets.transformersJS, filter: true, }, - "trellis": { + trellis: { prettyLabel: "Trellis", repoName: "Trellis", repoUrl: "https://github.com/microsoft/TRELLIS", From 8d52bb7115828512b5685a1f182c80a4292cdfca Mon Sep 17 00:00:00 2001 From: Marc Robin Gruener <52225086+MarcGruener@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:21:55 +0100 Subject: [PATCH 95/97] Update hardware.ts to include Apple M4 Pro 64 GB (#1078) The Apple M4 Pro is available with 64 GB of unified memory in the Mac Mini: https://www.apple.com/shop/buy-mac/mac-mini/apple-m4-pro-chip-with-12-core-cpu-16-core-gpu-24gb-memory-512gb# --- packages/tasks/src/hardware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tasks/src/hardware.ts b/packages/tasks/src/hardware.ts index 9999b0aec..fc754ffaa 100644 --- a/packages/tasks/src/hardware.ts +++ b/packages/tasks/src/hardware.ts @@ -485,7 +485,7 @@ export const SKUS = { }, "Apple M4 Pro": { tflops: 9.2, - memory: [24, 48], + memory: [24, 48, 64], }, "Apple M4 Max": { tflops: 18.4, From 4284a55ff4b034a4e72602f9717fd40b898642cb Mon Sep 17 00:00:00 2001 From: Akarshan Biswas Date: Tue, 17 Dec 2024 22:01:34 +0530 Subject: [PATCH 96/97] Update hardware.ts - Add 4 Intel Arc GPUs (#1073) Added 4 details of Intel Arc GPUs including the recently launched battlemage GPUs. I did it via mobile. Please check for accuracies before merging. Thanks. Cc: @Vaibhavs10 --------- Co-authored-by: vb --- packages/tasks/src/hardware.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/tasks/src/hardware.ts b/packages/tasks/src/hardware.ts index fc754ffaa..3e8e16c29 100644 --- a/packages/tasks/src/hardware.ts +++ b/packages/tasks/src/hardware.ts @@ -307,6 +307,24 @@ export const SKUS = { memory: [16], }, }, + INTEL: { + "Arc A750": { + tflops: 34.41, + memory: [8], + }, + "Arc A770": { + tflops: 39.32, + memory: [8, 16], + }, + "Arc B570": { + tflops: 23.04, + memory: [10], + }, + "Arc B580": { + tflops: 27.34, + memory: [12], + }, + }, QUALCOMM: { "Snapdragon X Elite X1E-00-1DE": { tflops: 4.6, From 11274e4ed83b2af83149d83412322bd278096f3c Mon Sep 17 00:00:00 2001 From: coyotte508 Date: Sun, 22 Dec 2024 10:12:14 +0100 Subject: [PATCH 97/97] =?UTF-8?q?=F0=9F=9A=80=20fix=20deploy=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/inference-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/inference-publish.yml b/.github/workflows/inference-publish.yml index ce3ddd421..779f62976 100644 --- a/.github/workflows/inference-publish.yml +++ b/.github/workflows/inference-publish.yml @@ -54,7 +54,7 @@ jobs: git tag "inference-v$BUMPED_VERSION" - name: "Check Deps are published before publishing this package" - run: pnpm -w check-deps gguf + run: pnpm -w check-deps tasks - run: pnpm publish --no-git-checks . env: