Skip to content

Commit abafd5d

Browse files
Update UI of the three demos: faqGen, VisualQnA, and DocSum. (#1528)
Signed-off-by: WenjiaoYue <wenjiao.yue@intel.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 970b869 commit abafd5d

File tree

11 files changed

+179
-91
lines changed

11 files changed

+179
-91
lines changed

DocSum/ui/gradio/docsum_ui_gradio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ def render(self):
296296
audio_ui.render()
297297
with gr.TabItem("Upload Video"):
298298
video_ui.render()
299-
with gr.TabItem("Enter URL"):
300-
url_ui.render()
299+
# with gr.TabItem("Enter URL"):
300+
# url_ui.render()
301301

302302
return self.demo
303303

FaqGen/ui/svelte/src/lib/shared/Network.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export async function fetchTextStream(query: string | Blob, params: string, file
5252
}
5353
const reader = postResponse.body.getReader();
5454
const decoder = new TextDecoder("utf-8");
55+
5556
let done, value;
5657

5758
let buffer = ""; // Initialize a buffer
@@ -61,6 +62,7 @@ export async function fetchTextStream(query: string | Blob, params: string, file
6162

6263
// Decode chunk and append to buffer
6364
const chunk = decoder.decode(value, { stream: true });
65+
6466
buffer += chunk;
6567

6668
// Use regex to clean and extract data
@@ -72,6 +74,21 @@ export async function fetchTextStream(query: string | Blob, params: string, file
7274
})
7375
.filter((line) => line); // Remove empty lines
7476

77+
const validJsonChunks = cleanedChunks.filter((item) => {
78+
if (item === "[DONE]") {
79+
return true;
80+
}
81+
try {
82+
JSON.parse(item);
83+
return true;
84+
} catch (e) {
85+
return false;
86+
}
87+
});
88+
89+
cleanedChunks.length = 0;
90+
cleanedChunks.push(...validJsonChunks);
91+
7592
for (const cleanedChunk of cleanedChunks) {
7693
// Further clean to ensure all unnecessary parts are removed
7794
yield cleanedChunk.replace(/^b'|['"]$/g, ""); // Again clean 'b' and other single or double quotes

FaqGen/ui/svelte/src/routes/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
urlSuffix: string,
3737
params: string
3838
) => {
39+
messages = "";
3940
// Fetch the stream
4041
const eventStream = await fetchTextStream(
4142
query,

VisualQnA/ui/svelte/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@tailwindcss/typography": "0.5.7",
2424
"@types/debug": "4.1.7",
2525
"@types/node": "^20.12.13",
26+
"@types/pica": "^9.0.5",
2627
"@typescript-eslint/eslint-plugin": "^5.27.0",
2728
"@typescript-eslint/parser": "^5.27.0",
2829
"autoprefixer": "^10.4.16",
@@ -51,6 +52,7 @@
5152
"flowbite-svelte-icons": "^1.4.0",
5253
"fuse.js": "^6.6.2",
5354
"lodash": "^4.17.21",
55+
"pica": "^9.0.1",
5456
"playwright": "^1.44.0",
5557
"ramda": "^0.29.0",
5658
"sse.js": "^0.6.1",
Binary file not shown.
Loading
Binary file not shown.
Loading

VisualQnA/ui/svelte/src/lib/modules/chat/ChatMessage.svelte

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@
3131
class={msg.role === 0
3232
? "flex w-full gap-3"
3333
: "flex w-full items-center gap-3"}
34-
data-testid={msg.role === 0
35-
? "display-answer"
36-
: "display-question"}
34+
data-testid={msg.role === 0 ? "display-answer" : "display-question"}
3735
>
3836
<div
3937
class={msg.role === 0
@@ -44,10 +42,15 @@
4442
</div>
4543
<div class="group relative flex items-start">
4644
<div class="flex flex-col items-start">
47-
<img src={msg.imgSrc} alt="Uploaded Image" class="m-2 max-w-28 max-h-28" />
48-
45+
{#if msg.imgSrc}
46+
<img
47+
src={msg.imgSrc}
48+
alt="Uploaded Image"
49+
class="max-w-28 m-2 max-h-28"
50+
/>
51+
{/if}
4952
<p
50-
class="xl:max-w-[65vw] max-w-[60vw] items-start whitespace-pre-line break-keep text-[0.8rem] leading-5 sm:max-w-[50rem]"
53+
class="max-w-[60vw] items-start whitespace-pre-line break-keep text-[0.8rem] leading-5 sm:max-w-[50rem] xl:max-w-[65vw]"
5154
>
5255
{@html msg.content}
5356
</p>

VisualQnA/ui/svelte/src/lib/modules/upload/imagePrompt.svelte

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,93 +5,98 @@
55

66
<script>
77
import { createEventDispatcher } from "svelte";
8-
import extreme_ironing from '$lib/assets/imageData/extreme_ironing.jpg';
9-
import waterview from '$lib/assets/imageData/waterview.jpg';
8+
import extreme_ironing from "$lib/assets/imageData/extreme_ironing.png";
9+
import waterview from "$lib/assets/imageData/waterview.png";
1010
import { base64ImageStore } from "$lib/shared/stores/common/Store";
1111
12-
let dispatch = createEventDispatcher();
12+
let dispatch = createEventDispatcher();
1313
14-
let images = [
15-
{
16-
id: 1,
17-
alt: 'Waterview',
18-
imgurl: waterview,
19-
prompt: 'What are the things I should be cautious about when I visit here?'
20-
},
21-
{
22-
id: 0,
23-
alt: 'Extreme Ironing',
24-
imgurl: extreme_ironing,
25-
prompt: 'What is unusual about this image?'
26-
}
27-
];
14+
let images = [
15+
{
16+
id: 1,
17+
alt: "Waterview",
18+
imgurl: waterview,
19+
prompt:
20+
"What are the things I should be cautious about when I visit here?",
21+
},
22+
{
23+
id: 0,
24+
alt: "Extreme Ironing",
25+
imgurl: extreme_ironing,
26+
prompt: "What is unusual about this image?",
27+
},
28+
];
2829
29-
let currentIndex = 0;
30+
let currentIndex = 0;
3031
31-
function nextImage() {
32-
currentIndex = (currentIndex + 1) % images.length;
33-
}
32+
function nextImage() {
33+
currentIndex = (currentIndex + 1) % images.length;
34+
}
3435
35-
function prevImage() {
36-
currentIndex = (currentIndex - 1 + images.length) % images.length;
37-
}
36+
function prevImage() {
37+
currentIndex = (currentIndex - 1 + images.length) % images.length;
38+
}
3839
40+
async function handleImageClick() {
41+
const imgUrl = images[currentIndex].imgurl;
3942
40-
async function handleImageClick() {
41-
const imgUrl = images[currentIndex].imgurl;
42-
const base64Data = await convertImageToBase64(imgUrl);
43-
const currentPrompt = images[currentIndex].prompt;
44-
dispatch("imagePrompt", { content: currentPrompt });
45-
base64ImageStore.set(base64Data);
46-
}
43+
const base64Data = await convertImageToBase64(imgUrl);
4744
48-
async function convertImageToBase64(url) {
49-
const response = await fetch(url);
50-
const blob = await response.blob();
51-
return new Promise((resolve, reject) => {
52-
const reader = new FileReader();
53-
reader.onloadend = () => resolve(reader.result);
54-
reader.onerror = reject;
55-
reader.readAsDataURL(blob);
56-
});
57-
}
45+
base64ImageStore.set(base64Data);
46+
47+
const currentPrompt = images[currentIndex].prompt;
48+
dispatch("imagePrompt", { content: currentPrompt });
49+
}
50+
51+
async function convertImageToBase64(url) {
52+
const response = await fetch(url);
53+
const blob = await response.blob();
54+
return new Promise((resolve, reject) => {
55+
const reader = new FileReader();
56+
reader.onloadend = () => resolve(reader.result);
57+
reader.onerror = reject;
58+
reader.readAsDataURL(blob);
59+
});
60+
}
5861
</script>
5962

60-
<div class="flex w-full flex-col gap-3 rounded-xl bg-white p-5 my-2">
61-
<p>Example</p>
62-
<div class="relative w-full max-w-4xl mx-auto">
63-
<button
64-
class="absolute left-0 top-1/2 transform -translate-y-1/2 z-10 w-8 h-8 rounded-full sm:w-10 sm:h-10 bg-white/30 dark:bg-gray-800/30 group-hover:bg-white/50 dark:group-hover:bg-gray-800/60 group-focus:ring-4 group-focus:ring-white dark:group-focus:ring-gray-800/70 group-focus:outline-none"
65-
on:click={prevImage}
66-
aria-label="Previous image"
67-
>
68-
&#10094;
69-
</button>
63+
<div class="my-2 flex w-full flex-col gap-3 rounded-xl bg-white p-5">
64+
<p>Example</p>
65+
<div class="relative mx-auto w-full max-w-4xl">
66+
<button
67+
class="absolute left-0 top-1/2 z-10 h-8 w-8 -translate-y-1/2 transform rounded-full bg-white/30 group-hover:bg-white/50 group-focus:outline-none group-focus:ring-4 group-focus:ring-white dark:bg-gray-800/30 dark:group-hover:bg-gray-800/60 dark:group-focus:ring-gray-800/70 sm:h-10 sm:w-10"
68+
on:click={prevImage}
69+
aria-label="Previous image"
70+
>
71+
&#10094;
72+
</button>
7073

71-
<div class="relative">
72-
<img
73-
src={images[currentIndex].imgurl}
74-
alt={images[currentIndex].alt}
75-
class="carousel-image w-full h-auto cursor-pointer"
76-
on:click={handleImageClick}
77-
/>
78-
<div class="absolute bottom-0 left-0 bg-opacity-55 bg-black text-white p-3 w-full">
79-
<p>{images[currentIndex].prompt}</p>
80-
</div>
81-
</div>
74+
<div class="relative">
75+
<img
76+
src={images[currentIndex].imgurl}
77+
alt={images[currentIndex].alt}
78+
class="carousel-image h-auto w-full cursor-pointer"
79+
on:click={handleImageClick}
80+
/>
81+
<div
82+
class="absolute bottom-0 left-0 w-full bg-black bg-opacity-55 p-3 text-white"
83+
>
84+
<p>{images[currentIndex].prompt}</p>
85+
</div>
86+
</div>
8287

83-
<button
84-
class="absolute right-0 top-1/2 transform -translate-y-1/2 z-10 w-8 h-8 rounded-full sm:w-10 sm:h-10 bg-white/30 dark:bg-gray-800/30 group-hover:bg-white/50 dark:group-hover:bg-gray-800/60 group-focus:ring-4 group-focus:ring-white dark:group-focus:ring-gray-800/70 group-focus:outline-none"
85-
on:click={nextImage}
86-
aria-label="Next image"
87-
>
88-
&#10095;
89-
</button>
90-
</div>
88+
<button
89+
class="absolute right-0 top-1/2 z-10 h-8 w-8 -translate-y-1/2 transform rounded-full bg-white/30 group-hover:bg-white/50 group-focus:outline-none group-focus:ring-4 group-focus:ring-white dark:bg-gray-800/30 dark:group-hover:bg-gray-800/60 dark:group-focus:ring-gray-800/70 sm:h-10 sm:w-10"
90+
on:click={nextImage}
91+
aria-label="Next image"
92+
>
93+
&#10095;
94+
</button>
95+
</div>
9196
</div>
9297

9398
<style>
94-
.relative img {
95-
object-fit: cover;
96-
}
99+
.relative img {
100+
object-fit: cover;
101+
}
97102
</style>

VisualQnA/ui/svelte/src/lib/modules/upload/uploadImg.svelte

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
<script lang="ts">
77
import { base64ImageStore } from "$lib/shared/stores/common/Store";
88
import { Dropzone } from "flowbite-svelte";
9+
import Pica from 'pica';
910
1011
let value = [];
1112
export let imageUrl = "";
1213
13-
$: if (imageUrl) {
14+
$: if (imageUrl !== "") {
1415
uploadImage();
1516
}
1617
@@ -47,22 +48,81 @@
4748
};
4849
4950
const handleChange = (event) => {
50-
const files = event.target.files;
51+
const files = event.target.files;
5152
if (files.length > 0) {
5253
value = [files[0].name]; // Allow only one file selection
5354
readFileAsBase64(files[0]); // Convert to Base64
5455
}
5556
};
5657
5758
const readFileAsBase64 = (file) => {
58-
const reader = new FileReader();
59-
reader.onload = () => {
60-
const base64Data = reader.result; // Get Base64 data
61-
base64ImageStore.set(base64Data); // Store the Base64 string in the store
62-
imageUrl = URL.createObjectURL(file); // Keep the object URL for preview
63-
};
64-
reader.readAsDataURL(file); // Read the file as a Data URL
65-
};
59+
const reader = new FileReader();
60+
reader.onload = () => {
61+
const base64Data = reader.result;
62+
const fileType = file.type;
63+
64+
if (!fileType.includes("png")) {
65+
convertImageToPNG(base64Data); // Convert if not PNG
66+
} else {
67+
base64ImageStore.set(base64Data); // Store Base64
68+
}
69+
70+
imageUrl = URL.createObjectURL(file); // Create URL for preview
71+
};
72+
reader.readAsDataURL(file); // Read file as Data URL
73+
};
74+
75+
const convertImageToPNG = async (base64Data) => {
76+
if (!base64Data || !base64Data.startsWith("data:image/")) {
77+
console.error("Invalid Base64 data");
78+
return;
79+
}
80+
81+
console.log("Starting image conversion...");
82+
83+
const img = new Image();
84+
img.src = base64Data;
85+
86+
img.onload = async () => {
87+
const canvas = document.createElement("canvas");
88+
const ctx = canvas.getContext("2d");
89+
let width = img.width;
90+
let height = img.height;
91+
92+
// Set resize factor to 1 (no scaling) to keep the original size
93+
const scaleFactor = 0.1; // Resize factor (keep original size)
94+
width = Math.floor(width * scaleFactor);
95+
height = Math.floor(height * scaleFactor);
96+
97+
canvas.width = width;
98+
canvas.height = height;
99+
100+
ctx.drawImage(img, 0, 0, width, height); // Draw the original image (no resizing)
101+
102+
const outputCanvas = document.createElement("canvas");
103+
outputCanvas.width = width;
104+
outputCanvas.height = height;
105+
106+
const pica = new Pica();
107+
108+
try {
109+
// Resize and compress the image using Pica
110+
await pica.resize(canvas, outputCanvas);
111+
112+
// Convert canvas to PNG format with data URL
113+
const pngDataUrl = outputCanvas.toDataURL("image/png", 0.8); // Adjust quality (0.9 is high, between 0-1)
114+
115+
// Store the Base64 PNG image
116+
base64ImageStore.set(pngDataUrl);
117+
} catch (err) {
118+
console.error("Error during image processing:", err);
119+
}
120+
};
121+
122+
img.onerror = (err) => {
123+
console.error("Error loading image:", err);
124+
};
125+
};
66126
67127
const showFiles = (files) => {
68128
if (files.length === 1) return files[0];

0 commit comments

Comments
 (0)