Skip to content

feat(frontend): add HuggingFace task selector and model browser component#5566

Merged
xuang7 merged 16 commits into
apache:mainfrom
ELin2025:hf/06a-frontend-selector
Jun 29, 2026
Merged

feat(frontend): add HuggingFace task selector and model browser component#5566
xuang7 merged 16 commits into
apache:mainfrom
ELin2025:hf/06a-frontend-selector

Conversation

@ELin2025

@ELin2025 ELin2025 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Add HuggingFaceComponent, a custom formly field type (huggingface) that provides:

  • A task dropdown listing all supported HuggingFace inference tasks (fetched from the Texera backend's /huggingface/tasks endpoint, with a static fallback list)
  • A paginated model list with client-side search, fetched from the Texera backend's /huggingface/models endpoint (which proxies HuggingFace Hub)
  • Per-task field state preservation — when switching tasks, previously entered values (modelId, promptColumn, etc.) are saved and restored

This PR registers the component in formly-config.ts and declares it in AppModule. The component is not yet wired into the HuggingFace operator's property editor; the jsonSchemaMapIntercept mapping that routes the modelId field to this component is added in the follow-up property-editor PR (PR 7).

Any related issues, documentation, discussions?

How was this PR tested?

7 unit tests added in hugging-face.component.spec.ts covering:

  • Static task list is non-empty and contains expected tasks (text-generation, image tasks, audio tasks, QA/ranking tasks)
  • Task tags are unique
  • Cache invalidation does not throw

Run with ng test.

Was this PR authored or co-authored using generative AI tooling?

Co-authored with Claude Opus 4.7

@codecov-commenter

codecov-commenter commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.75573% with 111 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.78%. Comparing base (613b76e) to head (8778aa2).

Files with missing lines Patch % Lines
...e/component/hugging-face/hugging-face.component.ts 67.22% 65 Missing and 32 partials ⚠️
...component/hugging-face/hugging-face.component.html 85.41% 12 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5566      +/-   ##
============================================
+ Coverage     56.67%   56.78%   +0.11%     
  Complexity     3026     3026              
============================================
  Files          1124     1126       +2     
  Lines         43292    43685     +393     
  Branches       4665     4729      +64     
============================================
+ Hits          24535    24808     +273     
- Misses        17319    17402      +83     
- Partials       1438     1475      +37     
Flag Coverage Δ *Carryforward flag
access-control-service 70.00% <ø> (ø) Carriedforward from 613b76e
agent-service 44.59% <ø> (ø) Carriedforward from 613b76e
amber 58.61% <ø> (ø) Carriedforward from 613b76e
computing-unit-managing-service 0.00% <ø> (ø) Carriedforward from 613b76e
config-service 52.30% <ø> (ø) Carriedforward from 613b76e
file-service 62.81% <ø> (ø) Carriedforward from 613b76e
frontend 49.90% <71.75%> (+0.45%) ⬆️
notebook-migration-service 78.57% <ø> (ø) Carriedforward from 613b76e
pyamber 90.20% <ø> (ø) Carriedforward from 613b76e
python 90.76% <ø> (ø) Carriedforward from 613b76e
workflow-compiling-service 55.14% <ø> (ø) Carriedforward from 613b76e

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ELin2025

ELin2025 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/request-review @Ma77Ball

1 similar comment
@ELin2025

ELin2025 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/request-review @Ma77Ball

@ELin2025 ELin2025 marked this pull request as draft June 8, 2026 22:15
@ELin2025 ELin2025 marked this pull request as ready for review June 8, 2026 22:30

@Ma77Ball Ma77Ball left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left comments, please ignore if implemented later or push those changes here.

Comment thread frontend/src/app/workspace/component/hugging-face/hugging-face.component.ts Outdated
Comment thread frontend/src/app/workspace/component/hugging-face/hugging-face.component.ts Outdated
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 2 better · 🔴 5 worse · ⚪ 8 noise (<±5%) · 0 without baseline

Compared against main 613b76e benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 392 0.239 24,173/43,249/43,249 us 🔴 +27.6% / 🔴 +187.0%
🟢 bs=100 sw=10 sl=64 943 0.576 104,695/124,653/124,653 us 🟢 -24.1% / 🔴 +14.5%
bs=1000 sw=10 sl=64 1,088 0.664 916,102/981,680/981,680 us ⚪ within ±5% / 🟢 -8.7%
Baseline details

Latest main 613b76e from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 392 tuples/sec 430 tuples/sec 770.82 tuples/sec -8.8% -49.1%
bs=10 sw=10 sl=64 MB/s 0.239 MB/s 0.262 MB/s 0.47 MB/s -8.8% -49.2%
bs=10 sw=10 sl=64 p50 24,173 us 22,396 us 12,723 us +7.9% +90.0%
bs=10 sw=10 sl=64 p95 43,249 us 33,885 us 15,070 us +27.6% +187.0%
bs=10 sw=10 sl=64 p99 43,249 us 33,885 us 18,429 us +27.6% +134.7%
bs=100 sw=10 sl=64 throughput 943 tuples/sec 940 tuples/sec 973.75 tuples/sec +0.3% -3.2%
bs=100 sw=10 sl=64 MB/s 0.576 MB/s 0.574 MB/s 0.594 MB/s +0.3% -3.1%
bs=100 sw=10 sl=64 p50 104,695 us 99,790 us 102,519 us +4.9% +2.1%
bs=100 sw=10 sl=64 p95 124,653 us 164,162 us 108,855 us -24.1% +14.5%
bs=100 sw=10 sl=64 p99 124,653 us 164,162 us 117,788 us -24.1% +5.8%
bs=1000 sw=10 sl=64 throughput 1,088 tuples/sec 1,113 tuples/sec 1,004 tuples/sec -2.2% +8.4%
bs=1000 sw=10 sl=64 MB/s 0.664 MB/s 0.679 MB/s 0.613 MB/s -2.2% +8.4%
bs=1000 sw=10 sl=64 p50 916,102 us 893,684 us 1,001,930 us +2.5% -8.6%
bs=1000 sw=10 sl=64 p95 981,680 us 939,068 us 1,042,923 us +4.5% -5.9%
bs=1000 sw=10 sl=64 p99 981,680 us 939,068 us 1,074,893 us +4.5% -8.7%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,509.86,200,128000,392,0.239,24172.93,43249.25,43249.25
1,100,10,64,20,2120.87,2000,1280000,943,0.576,104695.46,124652.52,124652.52
2,1000,10,64,20,18384.84,20000,12800000,1088,0.664,916101.59,981679.99,981679.99

@ELin2025 ELin2025 requested a review from Ma77Ball June 12, 2026 00:17

@Ma77Ball Ma77Ball left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Resolved since the last round:

  • interval/timeout handles tracked and cleared in ngOnDestroy
  • dead TASK_TAG_MAP/TASK_NAMES removed
  • truncation header read via observe: response, server-side search wired
  • inFlightByTag now used for dedup
  • tasks fetch resets its guard on cancellation via finalize

One item left, inline (suggestion). Static review only, not built or run.
@xuang7, can you review?

Comment thread frontend/src/app/workspace/component/hugging-face/hugging-face.component.ts Outdated
@ELin2025 ELin2025 force-pushed the hf/06a-frontend-selector branch from b132cde to 775f26c Compare June 16, 2026 18:07
@github-actions github-actions Bot added engine dependencies Pull requests that update a dependency file pyamber ci changes related to CI docs Changes related to documentations infra platform Non-amber Scala service paths agent-service labels Jun 16, 2026
@ELin2025 ELin2025 force-pushed the hf/06a-frontend-selector branch from 775f26c to b132cde Compare June 16, 2026 18:14
@github-actions github-actions Bot removed engine dependencies Pull requests that update a dependency file pyamber ci changes related to CI docs Changes related to documentations infra platform Non-amber Scala service paths labels Jun 16, 2026
@ELin2025

Copy link
Copy Markdown
Contributor Author

@xuang7 Added 38 TestBed integration tests (45 total, up from 7) covering task loading/error fallback, model loading/caching/truncation, pagination, local + server-side search, task selection with state snapshot/restore, and model selection.

@xuang7 xuang7 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! Please rebase onto the latest main and retarget the PR so the diff only includes the frontend selector changes.

@github-actions github-actions Bot removed the common label Jun 27, 2026
@ELin2025 ELin2025 force-pushed the hf/06a-frontend-selector branch from 0073ba1 to ffee92f Compare June 29, 2026 14:51
ELin2025 and others added 16 commits June 29, 2026 07:57
…nent

Register the huggingface formly field type and declare HuggingFaceComponent
in AppModule. Provides a task dropdown, paginated model list with client-side
search, and per-task field state preservation when switching tasks.
The rxjs/no-implicit-any-catch ESLint rule requires explicit type
annotations on error callbacks in .subscribe() calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mponent

Satisfies the rxjs-angular/prefer-takeuntil lint rule.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mponent

Fix setInterval/setTimeout leaks by tracking timer IDs and clearing them
in ngOnDestroy. Remove takeUntil(destroy$) from shared module-level task
fetch to prevent cache poisoning when the initiating component is destroyed.
Remove unused TASK_TAG_MAP and TASK_NAMES exports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…FaceComponent

inFlightByTag was written but never read, so multiple component instances
mounting for the same uncached task would each fire a full backend request.
Add an in-flight guard that polls for the existing request's completion,
matching the pattern already used for task fetches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… in HuggingFaceComponent

Read X-Texera-Truncated header via { observe: "response" } to detect
when the backend's model list is incomplete. Show a notice prompting
users to search. When truncated, search queries are sent to the backend
search endpoint with debounce; otherwise local filtering is used.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…r lint rule

Add back destroy$ and takeUntil(this.destroy$) on all subscribe calls.
For the shared task fetch, add finalize() to reset tasksFetchSubscription
when takeUntil fires before next/error, preventing the stale-guard bug
the reviewer originally flagged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…anup

Mirror the defensive pattern from the tasks fetch so that when
takeUntil(destroy$) cancels mid-flight, inFlightByTag is cleared
and subsequent component instances can re-fetch instead of polling
forever.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Elliot Lin <36275109+ELin2025@users.noreply.github.com>
- Fix model polling indefinite loop by detecting cancelled in-flight fetch
- Fix CSS class mismatch: hf-tasks-error → hf-error to match SCSS
- Remove unused imports in spec file

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Catch HTTP errors inside switchMap so search stream survives failures
- Use empty string instead of null when clearing model selection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 38 integration tests covering task loading, model loading,
pagination, search, task selection, and model selection logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Emit empty string through searchSubject$ in clearSearch(), onSearchInput(""),
and onTaskSelected() so switchMap cancels the pending HTTP request. Prevents
a late response from repopulating a cleared list or showing the wrong task's
models.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ELin2025 ELin2025 force-pushed the hf/06a-frontend-selector branch from ffee92f to 8778aa2 Compare June 29, 2026 14:59
@github-actions github-actions Bot removed the common label Jun 29, 2026
@ELin2025

Copy link
Copy Markdown
Contributor Author

@xuang7 Rebase and changes have been made

@xuang7 xuang7 added this pull request to the merge queue Jun 29, 2026
Merged via the queue into apache:main with commit d10e1a2 Jun 29, 2026
19 checks passed
roshiiiz pushed a commit to roshiiiz/texera that referenced this pull request Jun 29, 2026
### What changes were proposed in this PR?

Add `HuggingFaceAudioUploadComponent`, a custom formly field type
(`huggingface-audio-upload`) that provides:
- An audio file picker that uploads to the Texera backend's
`/huggingface/upload-audio` endpoint for server-side storage
- Authenticated audio preview/playback — fetches server-stored audio via
`HttpClient` (which carries the JWT) and creates a blob URL for the
`<audio>` element, avoiding 401s on workflow reload
- Local audio preview using a browser Object URL while upload is in
progress
- Stale response guards — discards upload results and preview fetches if
the user clears the field while a request is in flight
- Concurrent upload protection — disables the file input and Clear
button during upload
- Storage of the returned server path in the formly form control
- A guidance message explaining why audio is uploaded to backend storage
rather than embedded in the workflow JSON

This PR also registers `HuggingFaceComponent` and
`HuggingFaceAudioUploadComponent` in `formly-config.ts` and declares
them in `AppModule`. The `jsonSchemaMapIntercept` mapping that routes
the `audioInput` field to this component is added in the follow-up
property-editor PR (PR 7).

### Any related issues, documentation, discussions?

- Tracking issue: apache#5314
- Closes: apache#5314 
- Stacked on: apache#5566
- Parent issue: apache#5041

### How was this PR tested?

38 unit tests in `hugging-face-audio-upload.component.spec.ts` covering:
- `ngOnInit` — filename extraction from server paths, data URLs,
empty/whitespace values
- `previewSrc` — returns data URLs as-is, empty for server paths (loaded
async), empty for blank values
- `onFileSelected` — successful upload, non-audio rejection, concurrent
upload guard, no-file guard, upload-in-progress state, error handling,
filename fallback, model updates, Content-Type/URL encoding
- `loadServerAudioPreview` — successful blob fetch, fetch failure error
message, stale response discard on both success and error, no-fetch for
data URLs, URL encoding
- `clearAudio` — full state reset, error preservation, model clearing,
dirty/touched marking
- Stale upload guards — discard success/error when cleared during flight
- `ngOnDestroy` — blob URL revocation
- `getDisplayName` — forward/backslash paths, trailing separator, flat
filename

Run with `ng test`.

### Was this PR authored or co-authored using generative AI tooling?

Co-authored with Claude Opus 4.6

---------

Co-authored-by: Elliot <36275109+Falcons-Royale@users.noreply.github.com>
Co-authored-by: Anish Shivamurthy <anish@uci.edu>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mrudhulraj pushed a commit to Mrudhulraj/texera that referenced this pull request Jun 30, 2026
…nent (apache#5566)

⚠️ This PR is stacked on apache#5574. Until that lands, the diff below may
also include PR 5's QA/ranking task changes depending on which base
GitHub is showing. The new code in this PR is the HuggingFaceComponent
(task selector + model browser) under
frontend/src/app/workspace/component/hugging-face/, plus the formly
registration in formly-config.ts and the declaration in app.module.ts.
Once PR apache#5574 merges and this PR is retargeted to main, the diff should
auto-clean to the PR 6a frontend selector changes only.

### What changes were proposed in this PR?

Add `HuggingFaceComponent`, a custom formly field type (`huggingface`)
that provides:
- A task dropdown listing all supported HuggingFace inference tasks
(fetched from the Texera backend's `/huggingface/tasks` endpoint, with a
static fallback list)
- A paginated model list with client-side search, fetched from the
Texera backend's `/huggingface/models` endpoint (which proxies
HuggingFace Hub)
- Per-task field state preservation — when switching tasks, previously
entered values (modelId, promptColumn, etc.) are saved and restored

This PR registers the component in `formly-config.ts` and declares it in
`AppModule`. The component is not yet wired into the HuggingFace
operator's property editor; the `jsonSchemaMapIntercept` mapping that
routes the `modelId` field to this component is added in the follow-up
property-editor PR (PR 7).

### Any related issues, documentation, discussions?

- Tracking issue: apache#5314
- Closes: apache#5314
- Stacked on: PR tracked in issue apache#5292
- Parent issue: apache#5041

### How was this PR tested?

7 unit tests added in `hugging-face.component.spec.ts` covering:
- Static task list is non-empty and contains expected tasks
(text-generation, image tasks, audio tasks, QA/ranking tasks)
- Task tags are unique
- Cache invalidation does not throw

Run with `ng test`.

### Was this PR authored or co-authored using generative AI tooling?

Co-authored with Claude Opus 4.7

---------

Signed-off-by: Elliot Lin <36275109+ELin2025@users.noreply.github.com>
Co-authored-by: Elliot <36275109+Falcons-Royale@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Mrudhulraj pushed a commit to Mrudhulraj/texera that referenced this pull request Jun 30, 2026
### What changes were proposed in this PR?

Add `HuggingFaceAudioUploadComponent`, a custom formly field type
(`huggingface-audio-upload`) that provides:
- An audio file picker that uploads to the Texera backend's
`/huggingface/upload-audio` endpoint for server-side storage
- Authenticated audio preview/playback — fetches server-stored audio via
`HttpClient` (which carries the JWT) and creates a blob URL for the
`<audio>` element, avoiding 401s on workflow reload
- Local audio preview using a browser Object URL while upload is in
progress
- Stale response guards — discards upload results and preview fetches if
the user clears the field while a request is in flight
- Concurrent upload protection — disables the file input and Clear
button during upload
- Storage of the returned server path in the formly form control
- A guidance message explaining why audio is uploaded to backend storage
rather than embedded in the workflow JSON

This PR also registers `HuggingFaceComponent` and
`HuggingFaceAudioUploadComponent` in `formly-config.ts` and declares
them in `AppModule`. The `jsonSchemaMapIntercept` mapping that routes
the `audioInput` field to this component is added in the follow-up
property-editor PR (PR 7).

### Any related issues, documentation, discussions?

- Tracking issue: apache#5314
- Closes: apache#5314 
- Stacked on: apache#5566
- Parent issue: apache#5041

### How was this PR tested?

38 unit tests in `hugging-face-audio-upload.component.spec.ts` covering:
- `ngOnInit` — filename extraction from server paths, data URLs,
empty/whitespace values
- `previewSrc` — returns data URLs as-is, empty for server paths (loaded
async), empty for blank values
- `onFileSelected` — successful upload, non-audio rejection, concurrent
upload guard, no-file guard, upload-in-progress state, error handling,
filename fallback, model updates, Content-Type/URL encoding
- `loadServerAudioPreview` — successful blob fetch, fetch failure error
message, stale response discard on both success and error, no-fetch for
data URLs, URL encoding
- `clearAudio` — full state reset, error preservation, model clearing,
dirty/touched marking
- Stale upload guards — discard success/error when cleared during flight
- `ngOnDestroy` — blob URL revocation
- `getDisplayName` — forward/backslash paths, trailing separator, flat
filename

Run with `ng test`.

### Was this PR authored or co-authored using generative AI tooling?

Co-authored with Claude Opus 4.6

---------

Co-authored-by: Elliot <36275109+Falcons-Royale@users.noreply.github.com>
Co-authored-by: Anish Shivamurthy <anish@uci.edu>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend Changes related to the frontend GUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add HuggingFace task selector, model browser, and audio upload components

5 participants