Skip to content

Commit c4c64e0

Browse files
committed
Update the App component to hold textarea and set up model
1 parent f960df8 commit c4c64e0

File tree

1 file changed

+168
-8
lines changed

1 file changed

+168
-8
lines changed

vue/src/App.vue

Lines changed: 168 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,173 @@
1-
<script setup></script>
1+
<script setup>
2+
import { ref, onMounted, onUnmounted } from 'vue'
3+
import ProgressBar from './components/ProgressBar.vue'
4+
5+
const PLACEHOLDER_TEXT =
6+
'The tower is 324 metres (1,063 ft) tall, about the same height as an 81-storey building, and the tallest structure in Paris. Its base is square, measuring 125 metres (410 ft) on each side. During its construction, the Eiffel Tower surpassed the Washington Monument to become the tallest man-made structure in the world, a title it held for 41 years until the Chrysler Building in New York City was finished in 1930.'
7+
8+
const LOADING_MESSAGE = 'Loading models... (only run once)'
9+
const INPUT_ROWS = 6
10+
const OUTPUT_ROWS = 3
11+
12+
const ready = ref(null)
13+
const disabled = ref(false)
14+
const progressItems = ref([])
15+
const input = ref(PLACEHOLDER_TEXT)
16+
const output = ref('')
17+
const worker = ref(null)
18+
19+
onMounted(() => {
20+
worker.value ??= new Worker(new URL('./worker.js', import.meta.url), {
21+
type: 'module',
22+
})
23+
24+
/**
25+
* Handles messages received from the Web Worker
26+
* @param {MessageEvent} event - The message event from the worker
27+
*/
28+
const onMessageReceived = (event) => {
29+
switch (event.data.status) {
30+
case 'initiate':
31+
ready.value = false
32+
progressItems.value = [...progressItems.value, event.data]
33+
break
34+
35+
case 'progress':
36+
progressItems.value = progressItems.value.map((item) => {
37+
if (item.file === event.data.file) {
38+
return { ...item, progress: event.data.progress }
39+
}
40+
return item
41+
})
42+
break
43+
44+
case 'done':
45+
progressItems.value = progressItems.value.filter((item) => item.file !== event.data.file)
46+
break
47+
48+
case 'ready':
49+
ready.value = true
50+
break
51+
52+
case 'update':
53+
output.value += event.data.output
54+
break
55+
56+
case 'complete':
57+
disabled.value = false
58+
break
59+
}
60+
}
61+
62+
worker.value.addEventListener('message', onMessageReceived)
63+
64+
onUnmounted(() => worker.value?.removeEventListener('message', onMessageReceived))
65+
})
66+
67+
const summarize = () => {
68+
disabled.value = true
69+
output.value = ''
70+
worker.value.postMessage({
71+
text: input.value,
72+
})
73+
}
74+
</script>
275
376
<template>
4-
<div>
5-
<h1>You did it!</h1>
6-
<p>
7-
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
8-
documentation
9-
</p>
77+
<div class="app">
78+
<h1>Transformers.js</h1>
79+
<h2>ML-powered text summarization in Vue!</h2>
80+
81+
<div class="container">
82+
<div class="textbox-container">
83+
<textarea
84+
v-model="input"
85+
:rows="INPUT_ROWS"
86+
placeholder="Enter text to summarize..."
87+
></textarea>
88+
<textarea
89+
:value="output"
90+
:rows="OUTPUT_ROWS"
91+
readonly
92+
placeholder="Summary will appear here..."
93+
></textarea>
94+
</div>
95+
</div>
96+
97+
<button :disabled="disabled" @click="summarize">Summarize</button>
98+
99+
<div class="progress-bars-container">
100+
<label v-if="ready === false">{{ LOADING_MESSAGE }}</label>
101+
<div v-for="data in progressItems" :key="data.file">
102+
<ProgressBar :text="data.file" :percentage="data.progress" />
103+
</div>
104+
</div>
10105
</div>
11106
</template>
12107
13-
<style scoped></style>
108+
<style scoped>
109+
.app {
110+
font-family: Arial, Helvetica, sans-serif;
111+
max-width: 800px;
112+
margin: 40px auto;
113+
padding: 0 20px;
114+
text-align: center;
115+
}
116+
117+
.container {
118+
margin: 20px 0;
119+
}
120+
121+
.textbox-container {
122+
display: flex;
123+
flex-direction: column;
124+
gap: 20px;
125+
margin-bottom: 20px;
126+
}
127+
128+
textarea {
129+
width: 100%;
130+
padding: 12px;
131+
border: 2px solid #ccc;
132+
border-radius: 8px;
133+
font-size: 16px;
134+
font-family: inherit;
135+
resize: vertical;
136+
box-sizing: border-box;
137+
}
138+
139+
textarea:focus {
140+
outline: none;
141+
border-color: #4caf50;
142+
}
143+
144+
button {
145+
background-color: #4caf50;
146+
color: white;
147+
border: none;
148+
padding: 12px 24px;
149+
font-size: 16px;
150+
border-radius: 8px;
151+
cursor: pointer;
152+
transition: background-color 0.3s;
153+
}
154+
155+
button:hover:not(:disabled) {
156+
background-color: #45a049;
157+
}
158+
159+
button:disabled {
160+
background-color: #cccccc;
161+
cursor: not-allowed;
162+
}
163+
164+
.progress-bars-container {
165+
margin-top: 20px;
166+
}
167+
168+
.progress-bars-container label {
169+
display: block;
170+
margin-bottom: 10px;
171+
font-weight: bold;
172+
}
173+
</style>

0 commit comments

Comments
 (0)