Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Inference snippets] Templated snippets for inference snippet generation #1255

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

Wauplin
Copy link
Contributor

@Wauplin Wauplin commented Mar 6, 2025

What does this PR do?

  • add handlebars as a dependency for @huggingface/inference
  • heavily refactor ./packages/inference/src/snippets/python.ts to use templates instead of inline strings
  • add some snippet templates under packages/inference/src/snippets/templates/{language}/{client}/{templateName}.hbs
    • language is Python
    • client is e.g. huggingface_hub, requests, etc.
    • templateName is related to task name e.g. textToImage, conversationalStream, etc.

=> overall goal is to make it rather easy to update the snippets for a given task + client without entering the JS code
=> if conclusive, we can extend to cURL / JS snippets in a follow-up PR

This PR also includes a lot of small fixes (usually whitespace<>tabs inconsistencies) + added some tests. I did not change anything major in the generated snippets.

What to review?

IMO, no need to review all templates. Better to check the generated snippets + the main JS file directly (https://github.com/huggingface/huggingface.js/blob/ddd62b60d0a858dc808b6dd7b3589977681f5a8b/packages/inference/src/snippets/python.ts). Sorry for the huge PR but I do believe it is a necessary move moving forward 🤗

@@ -52,9 +52,11 @@
"check": "tsc"
},
"dependencies": {
"@huggingface/tasks": "workspace:^"
"@huggingface/tasks": "workspace:^",
"handlebars": "^4.7.8"
Copy link
Member

@julien-c julien-c Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @xenova

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be awesome! 🤩 Although the library was originally designed for ChatML templates, the set of available features should be large enough for these templates.

Maybe @Wauplin can explain what set of features would be required? 👀

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically just ifs and variable replacement from what i've seen

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handlebars has pretty much a feature set of 0.00

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea I'm really wary of adding more deps, if we can use jinja it would be great (and we could use jinja for more things)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update my PR tomorrow in that direction. As Julien said, I'm not using anything fancy at all so jinja will be more than enough for the job

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! Let me know if I can help in any way 🫡

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the handlebars dependency by huggingface/jinja and it works like a charm! 86e787a Thanks for the package @xenova! 🤗

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well I now have error Couldn't find package "@huggingface/jinja@^0.3.3" required by "@huggingface/inference@*" on the "npm" registry. in the CI though jinja 0.3.3 is available on https://www.npmjs.com/package/@huggingface/jinja 🤔

import { Template } from "@huggingface/jinja";
import fs from "fs";
import path from "path";
import { existsSync as pathExists } from "node:fs";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node packages are not available in contexts other than NodeJS (eg, when using the package in the web browser)

@coyotte508: is this an issue here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, I haven't done anything special to be sure the jinja files are exported in the js package. In Python one would need to explicitly set them as package_data in the setup.py but in JS I don't know what should be done

Copy link
Member

@coyotte508 coyotte508 Mar 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure you don't want to make @huggingface/snippets a separate package that works in node-only context and then we don't care about the browser ^^ ? Or move all the snippets code to moon (just export the necessary function from inference)?

With Vite bundler we can do ?raw, with general syntax we can import JSON: https://nodejs.org/api/esm.html#data-imports

But for a general case, you have two solutions IMO:

  • Instead of jinja files, have TS files with export default "<jinja template">. Then you can do await import(...) inside the code. This may break in some bundlers but we only care about moon use?
  • Have a gen package (like tasks-gens) and then put all the templates in a TS or JSON file

(anyway at this point it's probably worth it to move the code to moon/separate package IMO, will also make the libs lighter for those that download it)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coyotte508 can't it be the build script that bundles the files together at build time? (just for browsers? or as an optional dependency?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think I'll go with a new package 😕
I prefer to have these things open-source instead of in moon-landing to make it easier for external contributions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or another (dumb?) idea:
@julien-c @coyotte508 what do you think of keeping this code in @huggingface/inference as done in this PR and add a check that raises an error if the code is not executed using nodejs (i.e. if templates not found). No-one will use it anyway, we won't document it and at least things will be kept open-source. No need for an extra package this way.

(keeping things OSS is good for external contributions but also easier to generate these pages: https://huggingface.co/docs/api-inference/tasks/audio-classification#using-the-api with public code here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1259 🙈 🙈 🙈

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any issue with just ignoring these modules during bundling for the web? 👀 That's what I do for transformers.js, and it seems to work well enough.

Co-authored-by: Simon Brandeis <[email protected]>
@Wauplin Wauplin mentioned this pull request Mar 7, 2025
// Helpers to find + load templates

const rootDirFinder = (): string => {
let currentPath = path.normalize(import.meta.url).replace("file:", "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if this will work with moon (import.meta.url), or if it's finally time to move from CJS to ESM cc @Pierrci

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you simply curious or actually wishing for it? x)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I think it will be fine, but I may be wrong!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants