feat(frontend): add HuggingFace task selector and model browser component#5566
Conversation
Codecov Report❌ Patch coverage is 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
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
/request-review @Ma77Ball |
1 similar comment
|
/request-review @Ma77Ball |
Ma77Ball
left a comment
There was a problem hiding this comment.
Left comments, please ignore if implemented later or push those changes here.
|
| 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
Ma77Ball
left a comment
There was a problem hiding this comment.
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?
b132cde to
775f26c
Compare
775f26c to
b132cde
Compare
|
@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
left a comment
There was a problem hiding this comment.
LGTM! Please rebase onto the latest main and retarget the PR so the diff only includes the frontend selector changes.
0073ba1 to
ffee92f
Compare
…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>
ffee92f to
8778aa2
Compare
|
@xuang7 Rebase and changes have been made |
### 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>
…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>
### 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>
What changes were proposed in this PR?
Add
HuggingFaceComponent, a custom formly field type (huggingface) that provides:/huggingface/tasksendpoint, with a static fallback list)/huggingface/modelsendpoint (which proxies HuggingFace Hub)This PR registers the component in
formly-config.tsand declares it inAppModule. The component is not yet wired into the HuggingFace operator's property editor; thejsonSchemaMapInterceptmapping that routes themodelIdfield 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.tscovering:Run with
ng test.Was this PR authored or co-authored using generative AI tooling?
Co-authored with Claude Opus 4.7