-
Notifications
You must be signed in to change notification settings - Fork 538
[Widget] Refactor WidgetWrapper
#384
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
Conversation
7bcd57d to
ac6faf3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not related to this PR, but is there any way to generate the validators from some sort of task-specific JSONschema (one for each task)?
i.e. we'd have a single source of truth to define the shape of inputs/outputs
Yes. There is a lib called ajv https://github.com/ajv-validator/ajv. But I think I/we can implement something simple/small in our use case.
indeed, that would be great. Can also be used to auto generate the docs page https://huggingface.co/docs/hub/models-widgets-examples#widget-examples |
|
maybe after we switch to using |
lol, going full circle (we used to use ajv before switching to Joi)
Yes why not, and anyways the single source of truth's idea is that it would also be used in our Python libraries (cc @Wauplin)
how complex/disruptive would this be? (and what the other advantages?) |
@huggingface/inference validates api-output. Does it also validate input to the api? Also, we need to validate widget inputs and outputs (which can differ from inference input/output). For instance, on Text2Img widget, inference output is fileBlob while example output is url to file |
The main advantage is putting in common the options (eg regarding cache, model loading) + making sure |
No (and no plan to), we rely on the type system for that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! I love that we pass a lot less props to WidgetWrapper each time.
Two main comments:
- about calling
getContextat top-level - about
form
The rest you are free to ignore if you want ^^
PS: we should probably fix the Icon links (lots of //) but that comes from an earlier PR
packages/widgets/src/lib/components/InferenceWidget/shared/WidgetWrapper/WidgetWrapper.svelte
Outdated
Show resolved
Hide resolved
packages/widgets/src/lib/components/InferenceWidget/shared/WidgetHeader/WidgetHeader.svelte
Outdated
Show resolved
Hide resolved
...omponents/InferenceWidget/widgets/AudioClassificationWidget/AudioClassificationWidget.svelte
Outdated
Show resolved
Hide resolved
...omponents/InferenceWidget/widgets/AudioClassificationWidget/AudioClassificationWidget.svelte
Outdated
Show resolved
Hide resolved
ff12e1c to
adaea0b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
|
Reviewing this now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice refactor.
I haven't tested all the widgets.
I was a bit confused at first by the examples logic living in WidgetHeader, but that's probably just a wording issue.
| {:else} | ||
| Minimize | ||
| {/if} | ||
| </button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rationale for removing the maximize feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can put it back. I thought that this feature was not being used anywhere (point 4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, I would have kept it as it was 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled in edb463b
packages/widgets/src/lib/components/InferenceWidget/shared/WidgetHeader/WidgetHeader.svelte
Outdated
Show resolved
Hide resolved
packages/widgets/src/lib/components/InferenceWidget/shared/helpers.ts
Outdated
Show resolved
Hide resolved
| applyWidgetExample(exampleFromQueryParams); | ||
| } else { | ||
| // run random widget example | ||
| const example = getWidgetExample<TWidgetExample>(model, validateExample); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use allExamples here no?
It's already extracted from the widget and validated
Will allow us to remove the validateExample & model props from this component too
| const example = getWidgetExample<TWidgetExample>(model, validateExample); | |
| const example = randomItem(allExamples); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled as part of f22f63e
| export let applyWidgetExample: (sample: TWidgetExample, opts?: ExampleRunOpts) => void = () => {}; | ||
| export let validateExample: (sample: WidgetExample) => sample is TWidgetExample = ( | ||
| sample | ||
| ): sample is TWidgetExample => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit confused by those defaults, maybe safer to have undefined as a default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled as part of f22f63e
| // if there are no examples with outputs AND model.inference !== InferenceDisplayability.Yes | ||
| // then widget will show InferenceDisplayability error to the user without showing anything else | ||
| if (isDisabled && !examples.length) { | ||
| $widgetNoInference[model.id] = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated to the current PR: do stores get persisted when refreshing the page?
What happens when the store value changes? (Are the consuming components getting updated?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do stores get persisted when refreshing the page?
Svelte stores don't persist.
What happens when the store value changes? (Are the consuming components getting updated?)
if a consuming component had UI or reactive statement dependent on a store, that UI or reactive statement gets updated when store gets a update
| let:isDisabled | ||
| let:modelLoadInfo | ||
| let:WidgetInfo | ||
| let:WidgetHeader | ||
| let:WidgetFooter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be simpler / cleaner if isDisabled / modelLoadInfo were in a store?
From what I understand they are only exposed to be "re-injected" in WidgetHeader / WidgetInfo, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled in 9861a29
…pers.ts Co-authored-by: Simon Brandeis <33657802+SBrandeis@users.noreply.github.com>
…getHeader/WidgetHeader.svelte Co-authored-by: Simon Brandeis <33657802+SBrandeis@users.noreply.github.com>
update: commit f22f63e Worked bit more on wording and var names WidgetExamples component is inside WidgetHeader. And there is a widget examples logic inside WidgetHeader that does: <script>
...
const validExamples = areThereValidWidgetExamples()
...
</script>
<div>
{if validExamples}
<WidgetExamples>
{/if}
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok LGTM
Sorry for the delay in reviewing
Note that different widgets for the same model on the same page will share some state due to stores
Refactor
WidgetWrapper(continuing the widget rewrite)
WidgetWrapper. Instead,WidgetWrapperis still kept but simplified. Specificlly,WidgetWrapperdoes 2 tasks: 1. common styling for all widgets (just likeAppinside moon); 2. gets a model status (is it loaded, loadable, or too big)WidgetWrapper, there is no longerWidgetHeaderorWidgetFooterinsideWidgetWrapper. Therefore, every widget has to explicitly callWidgetHeaderorWidgetFooter.WidgetExamplescomponent: 1. to use less reactive statements$:; 2. have better variable names (favouringexampleXYZoverinputSampleXYZ); 3.WidgetExampleshas the logic to run a random widget exampleonMount(previously, this logic was insideWidgetWrapper)WidgetFooter. I don't think anyone was using. But happy to put it back.