-
Notifications
You must be signed in to change notification settings - Fork 171
feat(frontend): add HuggingFace media output rendering in result panel #5675
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
Merged
Merged
Changes from all commits
Commits
Show all changes
70 commits
Select commit
Hold shift + click to select a range
046734f
feat(frontend): add HuggingFace task selector and model browser compo…
ELin2025 f933fbe
fix(frontend): add explicit type annotations to rxjs error callbacks
ELin2025 1f5a0f4
style(frontend): format HuggingFace component with prettier
ELin2025 11e7cb9
fix(frontend): add takeUntil to rxjs subscribe calls in HuggingFaceCo…
ELin2025 6742c3c
fix(frontend): fix memory leaks and remove dead code in HuggingFaceCo…
ELin2025 41c9179
style(frontend): format HuggingFaceComponent with prettier
ELin2025 7ce8500
fix(frontend): add in-flight dedup guard for model fetches in Hugging…
ELin2025 f383eed
feat(frontend): surface truncation notice and wire server-side search…
ELin2025 66edef8
fix(frontend): restore takeUntil on subscribes to satisfy rxjs-angula…
ELin2025 95b8e4b
fix(frontend): add finalize guard to model fetch for cancellation cle…
ELin2025 4284d6d
Potential fix for pull request finding
ELin2025 91b5dde
fix(frontend): address Copilot review feedback on HuggingFaceComponent
ELin2025 0223dc5
fix(frontend): handle search stream errors and fix clear model value
ELin2025 cf6c20f
style(frontend): format HuggingFaceComponent with prettier
ELin2025 a784f3d
test(frontend): add comprehensive TestBed tests for HuggingFaceComponent
ELin2025 b03abf2
feat(frontend): add HuggingFace audio upload component
ELin2025 d4eac94
style(frontend): format audio upload spec with prettier
ELin2025 e999d94
style(frontend): format audio upload HTML with prettier
ELin2025 e2a2dfb
fix(frontend): guard concurrent uploads and remove dead test in audio…
ELin2025 33c5d7a
test(frontend): add TestBed-based tests for HuggingFaceAudioUploadCom…
ELin2025 35d33eb
fix(frontend): guard against stale upload response after clear
ELin2025 c900e01
fix(frontend): disable file input and clear button during audio upload
ELin2025 59fe00d
test(frontend): add comprehensive tests for HuggingFaceAudioUploadCom…
ELin2025 a1d62ba
feat(frontend): add task-aware field visibility and preview to Huggin…
ELin2025 739a2c4
test(frontend): add HuggingFace visibility tests and mock operator data
ELin2025 9348b18
style(frontend): format spec files with prettier
ELin2025 01fae10
style(frontend): format property editor component with prettier
ELin2025 e1c16d1
fix(frontend): fix HuggingFace field visibility and add missing previ…
ELin2025 373d992
fix(frontend): add missing preview assets and guard deleted operator
ELin2025 f789c4b
fix(huggingface): use CANDIDATE_LABELS property for zero-shot image c…
ELin2025 caa6fdc
test(frontend): add HuggingFace field visibility and validator tests
ELin2025 3094d1e
test(frontend): add HuggingFace field visibility, validator, and prev…
ELin2025 a22b2f9
fix(auth): handle missing JWT claims
anishshiva7 352f9cf
feat(huggingFace): add image task family via ImageTaskCodegen
PG1204 6fbc4e7
chore: retrigger CI
PG1204 a0c1bb7
chore: retrigger CI
PG1204 ae2c738
chore: retrigger CI
PG1204 2a00c4a
feat(huggingFace): add HuggingFaceModelResource for model browsing an…
PG1204 66ada29
fix: address review feedback on HuggingFaceModelResource
PG1204 e451064
fix(huggingFace): cap heap usage on /media-proxy and /audio-preview
PG1204 a04f4e7
chore: retrigger CI
PG1204 0f5791c
chore(huggingFace): annotate HuggingFaceModelResource with @RolesAllowed
PG1204 b86ad62
style(frontend): format HuggingFace components with prettier
ELin2025 3a0a455
feat(frontend): render HuggingFace media results inline in the result…
juliethecao 9fd8db5
fix(frontend): use toBe(true/false) instead of toBeTrue/toBeFalse in …
juliethecao 9a5664b
fix(frontend): use observe: "response" to access HuggingFace response…
juliethecao b5ec846
fix(frontend): decouple shared HuggingFace tasks fetch from component…
juliethecao 6fa2a49
fix(frontend): guard against JSON.stringify returning undefined in re…
juliethecao 306aab6
fix(frontend): remove unused NgxJsonViewerModule, guard JSON.stringif…
juliethecao 0e8fc58
style(huggingFace): apply scalafmt formatting
juliethecao d6415b3
style(frontend): apply prettier formatting to result-panel-modal
juliethecao 82163e7
fix(frontend): satisfy rxjs-angular/prefer-takeuntil lint rule in Hug…
juliethecao 5634a94
fix(frontend): fetch remote HuggingFace media via HttpClient to send …
juliethecao 577eadb
test(frontend): increase patch coverage for HuggingFace and result-pa…
juliethecao 4f678b6
Merge branch 'main' into hf/08-result-media
juliethecao ccff397
style(frontend): format result-panel-modal files with prettier
juliethecao 81c371f
Merge branch 'hf/08-result-media' of https://github.com/ELin2025/texe…
juliethecao aa90b9c
Merge branch 'main' into hf/08-result-media
juliethecao fcdd816
test(frontend): fix merge collision syntax errors and add template co…
juliethecao e29bc6a
Merge remote-tracking branch 'origin/main' into hf/08-result-media
juliethecao 41239a2
test(frontend): add HuggingFace task preview template coverage for op…
juliethecao f7de529
Merge remote-tracking branch 'upstream/main' into hf/08-result-media
juliethecao 3d26f7a
test(frontend): cover video/image src bindings and per-entry copy but…
juliethecao 12cd926
Merge branch 'main' into hf/08-result-media
juliethecao 525a0ae
Update frontend/src/app/common/util/media-type.util.ts
juliethecao 6855b17
Revert "fix(auth): handle missing JWT claims"
juliethecao 6fc7087
fix(frontend): precompute result table cell media types and stop SSRF…
juliethecao dd8de0c
Merge branch 'main' into hf/08-result-media
juliethecao 26c7aa1
fix(frontend): key result table cellMediaTypes by row object instead …
juliethecao 501a6df
Merge branch 'main' into hf/08-result-media
juliethecao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| import { isAudioUrl, isImageUrl, isVideoUrl } from "./media-type.util"; | ||
|
|
||
| describe("isImageUrl", () => { | ||
| it("should return true for data:image/ data URLs", () => { | ||
| expect(isImageUrl("data:image/png;base64,abc123")).toBe(true); | ||
| expect(isImageUrl("data:image/jpeg;base64,abc123")).toBe(true); | ||
| expect(isImageUrl("data:image/webp;base64,abc123")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for common image file extensions", () => { | ||
| expect(isImageUrl("https://example.com/photo.png")).toBe(true); | ||
| expect(isImageUrl("https://example.com/photo.jpg")).toBe(true); | ||
| expect(isImageUrl("https://example.com/photo.jpeg")).toBe(true); | ||
| expect(isImageUrl("https://example.com/photo.gif")).toBe(true); | ||
| expect(isImageUrl("https://example.com/photo.webp")).toBe(true); | ||
| }); | ||
|
|
||
| it("should be case-insensitive for extensions", () => { | ||
| expect(isImageUrl("https://example.com/photo.PNG")).toBe(true); | ||
| expect(isImageUrl("https://example.com/photo.JPG")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for URLs with query strings", () => { | ||
| expect(isImageUrl("https://example.com/photo.png?v=1")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return false for audio and video URLs", () => { | ||
| expect(isImageUrl("data:audio/mp3;base64,abc")).toBe(false); | ||
| expect(isImageUrl("data:video/mp4;base64,abc")).toBe(false); | ||
| expect(isImageUrl("https://example.com/clip.mp4")).toBe(false); | ||
| }); | ||
|
|
||
| it("should return false for plain text strings", () => { | ||
| expect(isImageUrl("hello world")).toBe(false); | ||
| expect(isImageUrl("")).toBe(false); | ||
| }); | ||
| }); | ||
|
|
||
| describe("isAudioUrl", () => { | ||
| it("should return true for data:audio/ data URLs", () => { | ||
| expect(isAudioUrl("data:audio/mp3;base64,abc123")).toBe(true); | ||
| expect(isAudioUrl("data:audio/wav;base64,abc123")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for common audio file extensions", () => { | ||
| expect(isAudioUrl("https://example.com/clip.mp3")).toBe(true); | ||
| expect(isAudioUrl("https://example.com/clip.wav")).toBe(true); | ||
| expect(isAudioUrl("https://example.com/clip.ogg")).toBe(true); | ||
| expect(isAudioUrl("https://example.com/clip.m4a")).toBe(true); | ||
| expect(isAudioUrl("https://example.com/clip.flac")).toBe(true); | ||
| }); | ||
|
|
||
| it("should be case-insensitive for extensions", () => { | ||
| expect(isAudioUrl("https://example.com/clip.MP3")).toBe(true); | ||
| expect(isAudioUrl("https://example.com/clip.WAV")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for URLs with query strings", () => { | ||
| expect(isAudioUrl("https://example.com/clip.mp3?token=xyz")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return false for image and video URLs", () => { | ||
| expect(isAudioUrl("data:image/png;base64,abc")).toBe(false); | ||
| expect(isAudioUrl("data:video/mp4;base64,abc")).toBe(false); | ||
| expect(isAudioUrl("https://example.com/photo.png")).toBe(false); | ||
| }); | ||
|
|
||
| it("should return false for plain text strings", () => { | ||
| expect(isAudioUrl("hello world")).toBe(false); | ||
| expect(isAudioUrl("")).toBe(false); | ||
| }); | ||
| }); | ||
|
|
||
| describe("isVideoUrl", () => { | ||
| it("should return true for data:video/ data URLs", () => { | ||
| expect(isVideoUrl("data:video/mp4;base64,abc123")).toBe(true); | ||
| expect(isVideoUrl("data:video/webm;base64,abc123")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for common video file extensions", () => { | ||
| expect(isVideoUrl("https://example.com/clip.mp4")).toBe(true); | ||
| expect(isVideoUrl("https://example.com/clip.webm")).toBe(true); | ||
| expect(isVideoUrl("https://example.com/clip.ogv")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for fal.media CDN URLs", () => { | ||
| expect(isVideoUrl("https://v3b.fal.media/files/abc123/output.mp4")).toBe(true); | ||
| }); | ||
|
|
||
| it("should be case-insensitive for extensions", () => { | ||
| expect(isVideoUrl("https://example.com/clip.MP4")).toBe(true); | ||
| expect(isVideoUrl("https://example.com/clip.WEBM")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return true for URLs with query strings", () => { | ||
| expect(isVideoUrl("https://example.com/clip.mp4?t=5")).toBe(true); | ||
| }); | ||
|
|
||
| it("should return false for image and audio URLs", () => { | ||
| expect(isVideoUrl("data:image/png;base64,abc")).toBe(false); | ||
| expect(isVideoUrl("data:audio/mp3;base64,abc")).toBe(false); | ||
| expect(isVideoUrl("https://example.com/photo.jpg")).toBe(false); | ||
| }); | ||
|
|
||
| it("should return false for plain text strings", () => { | ||
| expect(isVideoUrl("hello world")).toBe(false); | ||
| expect(isVideoUrl("")).toBe(false); | ||
| }); | ||
|
|
||
| it("should return false for non-string types", () => { | ||
| expect(isVideoUrl(null as unknown as string)).toBe(false); | ||
| expect(isVideoUrl(undefined as unknown as string)).toBe(false); | ||
| expect(isVideoUrl(42 as unknown as string)).toBe(false); | ||
| }); | ||
| }); | ||
|
|
||
| describe("non-string type guard (shared)", () => { | ||
| it("isAudioUrl should return false for non-string types", () => { | ||
| expect(isAudioUrl(null as unknown as string)).toBe(false); | ||
| expect(isAudioUrl(undefined as unknown as string)).toBe(false); | ||
| expect(isAudioUrl(true as unknown as string)).toBe(false); | ||
| }); | ||
|
|
||
| it("isImageUrl should return false for non-string types", () => { | ||
| expect(isImageUrl(null as unknown as string)).toBe(false); | ||
| expect(isImageUrl(undefined as unknown as string)).toBe(false); | ||
| expect(isImageUrl([] as unknown as string)).toBe(false); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| export function isVideoUrl(value: string): boolean { | ||
| if (typeof value !== "string") return false; | ||
| return ( | ||
| /^https?:\/\/.+\.(mp4|webm|ogv)(\?.*)?$/i.test(value) || | ||
| value.startsWith("data:video/") || | ||
| /^https:\/\/[a-z0-9-]+\.fal\.media\/files\//i.test(value) | ||
| ); | ||
| } | ||
|
|
||
| export function isAudioUrl(value: string): boolean { | ||
| if (typeof value !== "string") return false; | ||
| return /^https?:\/\/.+\.(mp3|wav|ogg|m4a|flac)(\?.*)?$/i.test(value) || value.startsWith("data:audio/"); | ||
| } | ||
|
|
||
| export function isImageUrl(value: string): boolean { | ||
| if (typeof value !== "string") return false; | ||
| return /^https?:\/\/.+\.(png|jpg|jpeg|gif|webp)(\?.*)?$/i.test(value) || value.startsWith("data:image/"); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.