diff --git a/.github/workflows/inference-publish.yml b/.github/workflows/inference-publish.yml index bbf0a9c0f9..5ba3876456 100644 --- a/.github/workflows/inference-publish.yml +++ b/.github/workflows/inference-publish.yml @@ -52,6 +52,44 @@ jobs: git add ../.. git commit -m "๐Ÿ”– @hugginface/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 + - 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 158851022d..99df0df100 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,7 @@ jobs: run: | sleep 3 pnpm i --filter inference... --filter hub... --frozen-lockfile - pnpm --filter inference --filter hub 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/inference/package.json b/packages/inference/package.json index e01f556eeb..a5a26d1026 100644 --- a/packages/inference/package.json +++ b/packages/inference/package.json @@ -40,7 +40,7 @@ "type": "module", "scripts": { "build": "tsup src/index.ts --format cjs,esm --clean && pnpm run dts", - "dts": "tsx scripts/generate-dts.ts", + "dts": "tsx scripts/generate-dts.ts && tsc --noEmit dist/index.d.ts", "lint": "eslint --quiet --fix --ext .cjs,.ts .", "lint:check": "eslint --ext .cjs,.ts .", "format": "prettier --write .", @@ -51,8 +51,10 @@ "test:browser": "vitest run --browser.name=chrome --browser.headless --config vitest.config.mts", "check": "tsc" }, + "dependencies": { + "@huggingface/tasks": "workspace:^" + }, "devDependencies": { - "@huggingface/tasks": "workspace:^", "@types/node": "18.13.0" }, "resolutions": {} diff --git a/packages/inference/pnpm-lock.yaml b/packages/inference/pnpm-lock.yaml index ff6f90f72f..5bb56da2d1 100644 --- a/packages/inference/pnpm-lock.yaml +++ b/packages/inference/pnpm-lock.yaml @@ -4,10 +4,12 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -devDependencies: +dependencies: '@huggingface/tasks': specifier: workspace:^ version: link:../tasks + +devDependencies: '@types/node': specifier: 18.13.0 version: 18.13.0 diff --git a/packages/inference/scripts/generate-dts.ts b/packages/inference/scripts/generate-dts.ts index 82b732e85d..35427d5236 100644 --- a/packages/inference/scripts/generate-dts.ts +++ b/packages/inference/scripts/generate-dts.ts @@ -3,6 +3,8 @@ import { readFileSync, writeFileSync, appendFileSync, readdirSync } from "node:fs"; import { TASKS_DATA } from "@huggingface/tasks"; +const taskImports = new Set(); + const tasks = Object.keys(TASKS_DATA) .sort() .filter((task) => task !== "other"); @@ -36,6 +38,16 @@ for (const dir of dirs) { const fileContent = readFileSync(`./src/tasks/${dir}/${file}`, "utf-8"); + // detect imports from @huggingface/tasks + for (const imports of fileContent.matchAll(/import type {(.*)} from "@huggingface\/tasks";/g)) { + // Convert A, B, C to ["A", "B", "C"] + const imported = imports[1].split(",").map((x) => x.trim()); + + for (const imp of imported) { + taskImports.add(imp); + } + } + for (const type of extractTypesAndInterfaces(fileContent)) { appendFileSync("./dist/index.d.ts", type + "\n"); } @@ -87,6 +99,13 @@ appendFileSync( "\n}\n" ); +// Prepend import from @huggingface/tasks +writeFileSync( + "./dist/index.d.ts", + `import type { ${[...taskImports].join(", ")} } from "@huggingface/tasks";\n` + + readFileSync("./dist/index.d.ts", "utf-8") +); + function* extractTypesAndInterfaces(fileContent: string): Iterable { let index = 0; diff --git a/packages/inference/src/tasks/nlp/textGeneration.ts b/packages/inference/src/tasks/nlp/textGeneration.ts index 72a671c07c..cf6f30ab10 100644 --- a/packages/inference/src/tasks/nlp/textGeneration.ts +++ b/packages/inference/src/tasks/nlp/textGeneration.ts @@ -1,209 +1,9 @@ +import type { TextGenerationInput, TextGenerationOutput } from "@huggingface/tasks"; import { InferenceOutputError } from "../../lib/InferenceOutputError"; import type { BaseArgs, Options } from "../../types"; import { request } from "../custom/request"; -/** - * Inputs for Text Generation inference - */ -export interface TextGenerationInput { - /** - * The text to initialize generation with - */ - inputs: string; - /** - * Additional inference parameters - */ - parameters?: TextGenerationParameters; - /** - * Whether to stream output tokens - */ - stream?: boolean; - [property: string]: unknown; -} - -/** - * Additional inference parameters - * - * Additional inference parameters for Text Generation - */ -export interface TextGenerationParameters { - /** - * The number of sampling queries to run. Only the best one (in terms of total logprob) will - * be returned. - */ - best_of?: number; - /** - * Whether or not to output decoder input details - */ - decoder_input_details?: boolean; - /** - * Whether or not to output details - */ - details?: boolean; - /** - * Whether to use logits sampling instead of greedy decoding when generating new tokens. - */ - do_sample?: boolean; - /** - * The maximum number of tokens to generate. - */ - max_new_tokens?: number; - /** - * The parameter for repetition penalty. A value of 1.0 means no penalty. See [this - * paper](https://hf.co/papers/1909.05858) for more details. - */ - repetition_penalty?: number; - /** - * Whether to prepend the prompt to the generated text. - */ - return_full_text?: boolean; - /** - * The random sampling seed. - */ - seed?: number; - /** - * Stop generating tokens if a member of `stop_sequences` is generated. - */ - stop_sequences?: string[]; - /** - * The value used to modulate the logits distribution. - */ - temperature?: number; - /** - * The number of highest probability vocabulary tokens to keep for top-k-filtering. - */ - top_k?: number; - /** - * If set to < 1, only the smallest set of most probable tokens with probabilities that add - * up to `top_p` or higher are kept for generation. - */ - top_p?: number; - /** - * Truncate input tokens to the given size. - */ - truncate?: number; - /** - * Typical Decoding mass. See [Typical Decoding for Natural Language - * Generation](https://hf.co/papers/2202.00666) for more information - */ - typical_p?: number; - /** - * Watermarking with [A Watermark for Large Language Models](https://hf.co/papers/2301.10226) - */ - watermark?: boolean; - [property: string]: unknown; -} - -/** - * Outputs for Text Generation inference - */ -export interface TextGenerationOutput { - /** - * When enabled, details about the generation - */ - details?: TextGenerationOutputDetails; - /** - * The generated text - */ - generated_text: string; - [property: string]: unknown; -} - -/** - * When enabled, details about the generation - */ -export interface TextGenerationOutputDetails { - /** - * Details about additional sequences when best_of is provided - */ - best_of_sequences?: TextGenerationOutputSequenceDetails[]; - /** - * The reason why the generation was stopped. - */ - finish_reason: TextGenerationFinishReason; - /** - * The number of generated tokens - */ - generated_tokens: number; - prefill: TextGenerationPrefillToken[]; - /** - * The random seed used for generation - */ - seed?: number; - /** - * The generated tokens and associated details - */ - tokens: TextGenerationOutputToken[]; - /** - * Most likely tokens - */ - top_tokens?: Array; - [property: string]: unknown; -} - -export interface TextGenerationOutputSequenceDetails { - finish_reason: TextGenerationFinishReason; - /** - * The generated text - */ - generated_text: string; - /** - * The number of generated tokens - */ - generated_tokens: number; - prefill: TextGenerationPrefillToken[]; - /** - * The random seed used for generation - */ - seed?: number; - /** - * The generated tokens and associated details - */ - tokens: TextGenerationOutputToken[]; - /** - * Most likely tokens - */ - top_tokens?: Array; - [property: string]: unknown; -} - -export interface TextGenerationPrefillToken { - id: number; - logprob: number; - /** - * The text associated with that token - */ - text: string; - [property: string]: unknown; -} - -/** - * Generated token. - */ -export interface TextGenerationOutputToken { - id: number; - logprob?: number; - /** - * Whether or not that token is a special one - */ - special: boolean; - /** - * The text associated with that token - */ - text: string; - [property: string]: unknown; -} - -/** - * The reason why the generation was stopped. - * - * length: The generated sequence reached the maximum allowed length - * - * eos_token: The model generated an end-of-sentence (EOS) token - * - * stop_sequence: One of the sequence in stop_sequences was generated - */ -export type TextGenerationFinishReason = "length" | "eos_token" | "stop_sequence"; +export type { TextGenerationInput, TextGenerationOutput }; /** * Use to continue text from a prompt. This is a very generic task. Recommended model: gpt2 (itโ€™s a simple model, but fun to play with). diff --git a/packages/inference/src/tasks/nlp/textGenerationStream.ts b/packages/inference/src/tasks/nlp/textGenerationStream.ts index 827083fcf8..f935bc34e8 100644 --- a/packages/inference/src/tasks/nlp/textGenerationStream.ts +++ b/packages/inference/src/tasks/nlp/textGenerationStream.ts @@ -1,6 +1,6 @@ +import type { TextGenerationInput } from "@huggingface/tasks"; import type { BaseArgs, Options } from "../../types"; import { streamingRequest } from "../custom/streamingRequest"; -import type { TextGenerationInput } from "./textGeneration"; export interface TextGenerationStreamToken { /** Token ID from the model tokenizer */