Skip to content

Commit 0419081

Browse files
committed
Add sound notification
1 parent 6aad522 commit 0419081

21 files changed

+220
-56
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<template>
2+
<FormFileUpload
3+
:modelValue="modelValue"
4+
@update:modelValue="emit('update:modelValue', $event)"
5+
inputAccept="audio/*"
6+
>
7+
<template #preview>
8+
<div
9+
class="preview-box border rounded p-2 w-16 h-16 flex items-center justify-center"
10+
:class="{ 'bg-gray-100 dark:bg-gray-800': !modelValue }"
11+
>
12+
<audio
13+
v-if="modelValue"
14+
:src="modelValue"
15+
class="max-w-full max-h-full object-contain"
16+
controls
17+
/>
18+
<i v-else class="pi pi-volume-up text-gray-400 text-xl"></i>
19+
</div>
20+
</template>
21+
</FormFileUpload>
22+
</template>
23+
24+
<script setup lang="ts">
25+
import FormFileUpload from './FormFileUpload.vue'
26+
27+
defineProps<{
28+
modelValue: string
29+
}>()
30+
31+
const emit = defineEmits<{
32+
(e: 'update:modelValue', value: string): void
33+
}>()
34+
</script>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<template>
2+
<div class="image-upload-wrapper">
3+
<div class="flex gap-2 items-center">
4+
<slot name="preview"></slot>
5+
6+
<div class="flex flex-col gap-2">
7+
<Button
8+
icon="pi pi-upload"
9+
:label="$t('g.upload')"
10+
size="small"
11+
@click="triggerFileInput"
12+
/>
13+
<Button
14+
v-if="modelValue"
15+
class="w-full"
16+
outlined
17+
icon="pi pi-trash"
18+
severity="danger"
19+
size="small"
20+
@click="clear"
21+
/>
22+
</div>
23+
</div>
24+
<input
25+
ref="fileInput"
26+
type="file"
27+
class="hidden"
28+
:accept="inputAccept"
29+
@change="handleFileUpload"
30+
/>
31+
</div>
32+
</template>
33+
34+
<script setup lang="ts">
35+
import Button from 'primevue/button'
36+
import { ref } from 'vue'
37+
38+
defineProps<{
39+
modelValue: string
40+
inputAccept: string
41+
}>()
42+
43+
const emit = defineEmits<{
44+
(e: 'update:modelValue', value: string): void
45+
}>()
46+
47+
const fileInput = ref<HTMLInputElement | null>(null)
48+
49+
const triggerFileInput = () => {
50+
fileInput.value?.click()
51+
}
52+
53+
const handleFileUpload = (event: Event) => {
54+
const target = event.target as HTMLInputElement
55+
if (target.files && target.files[0]) {
56+
const file = target.files[0]
57+
const reader = new FileReader()
58+
reader.onload = (e) => {
59+
emit('update:modelValue', e.target?.result as string)
60+
}
61+
reader.readAsDataURL(file)
62+
}
63+
}
64+
65+
const clear = () => {
66+
emit('update:modelValue', '')
67+
if (fileInput.value) {
68+
fileInput.value.value = ''
69+
}
70+
}
71+
</script>
Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<template>
2-
<div class="image-upload-wrapper">
3-
<div class="flex gap-2 items-center">
2+
<FormFileUpload
3+
:modelValue="modelValue"
4+
@update:modelValue="emit('update:modelValue', $event)"
5+
inputAccept="image/*"
6+
>
7+
<template #preview>
48
<div
59
class="preview-box border rounded p-2 w-16 h-16 flex items-center justify-center"
610
:class="{ 'bg-gray-100 dark:bg-gray-800': !modelValue }"
@@ -12,38 +16,12 @@
1216
/>
1317
<i v-else class="pi pi-image text-gray-400 text-xl"></i>
1418
</div>
15-
16-
<div class="flex flex-col gap-2">
17-
<Button
18-
icon="pi pi-upload"
19-
:label="$t('g.upload')"
20-
size="small"
21-
@click="triggerFileInput"
22-
/>
23-
<Button
24-
v-if="modelValue"
25-
class="w-full"
26-
outlined
27-
icon="pi pi-trash"
28-
severity="danger"
29-
size="small"
30-
@click="clearImage"
31-
/>
32-
</div>
33-
</div>
34-
<input
35-
ref="fileInput"
36-
type="file"
37-
class="hidden"
38-
accept="image/*"
39-
@change="handleFileUpload"
40-
/>
41-
</div>
19+
</template>
20+
</FormFileUpload>
4221
</template>
4322

4423
<script setup lang="ts">
45-
import Button from 'primevue/button'
46-
import { ref } from 'vue'
24+
import FormFileUpload from './FormFileUpload.vue'
4725
4826
defineProps<{
4927
modelValue: string
@@ -52,29 +30,4 @@ defineProps<{
5230
const emit = defineEmits<{
5331
(e: 'update:modelValue', value: string): void
5432
}>()
55-
56-
const fileInput = ref<HTMLInputElement | null>(null)
57-
58-
const triggerFileInput = () => {
59-
fileInput.value?.click()
60-
}
61-
62-
const handleFileUpload = (event: Event) => {
63-
const target = event.target as HTMLInputElement
64-
if (target.files && target.files[0]) {
65-
const file = target.files[0]
66-
const reader = new FileReader()
67-
reader.onload = (e) => {
68-
emit('update:modelValue', e.target?.result as string)
69-
}
70-
reader.readAsDataURL(file)
71-
}
72-
}
73-
74-
const clearImage = () => {
75-
emit('update:modelValue', '')
76-
if (fileInput.value) {
77-
fileInput.value.value = ''
78-
}
79-
}
8033
</script>

src/components/common/FormItem.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import ToggleSwitch from 'primevue/toggleswitch'
3737
import { type Component, markRaw } from 'vue'
3838

3939
import CustomFormValue from '@/components/common/CustomFormValue.vue'
40+
import FormAudioUpload from '@/components/common/FormAudioUpload.vue'
4041
import FormColorPicker from '@/components/common/FormColorPicker.vue'
4142
import FormImageUpload from '@/components/common/FormImageUpload.vue'
4243
import InputKnob from '@/components/common/InputKnob.vue'
@@ -98,6 +99,8 @@ function getFormComponent(item: FormItem): Component {
9899
return Select
99100
case 'image':
100101
return FormImageUpload
102+
case 'audio':
103+
return FormAudioUpload
101104
case 'color':
102105
return FormColorPicker
103106
case 'url':

src/extensions/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import './saveImageExtraOutput'
1414
import './saveMesh'
1515
import './simpleTouchSupport'
1616
import './slotDefaults'
17+
import './soundNotification'
1718
import './uploadAudio'
1819
import './uploadImage'
1920
import './webcamCapture'
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { StatusWsMessageStatus } from '../../schemas/apiSchema'
2+
import { api } from '../../scripts/api'
3+
import { app } from '../../scripts/app'
4+
5+
app.registerExtension({
6+
name: 'Comfy.SoundNotification',
7+
init() {
8+
app.ui.settings.addSetting({
9+
id: 'Comfy.SoundNotification.AfterOnePrompt',
10+
name: 'After executing a prompt',
11+
type: 'audio',
12+
defaultValue: undefined
13+
})
14+
app.ui.settings.addSetting({
15+
id: 'Comfy.SoundNotification.AfterAllPrompts',
16+
name: 'After executing all the prompts',
17+
type: 'audio',
18+
defaultValue: undefined
19+
})
20+
21+
let lastQueueRemaining: number = 0
22+
23+
function playAudio(settingId: string) {
24+
const soundData = app.ui.settings.getSettingValue(settingId)
25+
if (soundData) {
26+
new Audio(soundData).play()
27+
}
28+
}
29+
30+
api.addEventListener(
31+
'status',
32+
(event: CustomEvent<StatusWsMessageStatus>): void => {
33+
const queueRemaining = event.detail.exec_info.queue_remaining
34+
if (lastQueueRemaining > 0 && queueRemaining === 0) {
35+
// In order to prevent "AfterAllPrompts" sound from being played when another prompt is immediately queued,
36+
// checking again after a short delay.
37+
// TODO: more reliable way
38+
setTimeout(() => {
39+
if (lastQueueRemaining === 0) {
40+
playAudio('Comfy.SoundNotification.AfterAllPrompts')
41+
} else {
42+
playAudio('Comfy.SoundNotification.AfterOnePrompt')
43+
}
44+
}, 500)
45+
} else if (queueRemaining < lastQueueRemaining) {
46+
playAudio('Comfy.SoundNotification.AfterOnePrompt')
47+
}
48+
lastQueueRemaining = queueRemaining
49+
}
50+
)
51+
}
52+
})

src/locales/en/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@
704704
"Server": "Server",
705705
"Settings": "Settings",
706706
"Sidebar": "Sidebar",
707+
"SoundNotification": "Sound Notification",
707708
"Tree Explorer": "Tree Explorer",
708709
"Validation": "Validation",
709710
"Window": "Window",

src/locales/en/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "After executing all prompts"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "After executing a prompt"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "Automatically check for updates"
410
},

src/locales/es/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "Configuración del Servidor",
839839
"Settings": "Configuraciones",
840840
"Sidebar": "Barra Lateral",
841+
"SoundNotification": "Notificación de Sonido",
841842
"Tree Explorer": "Explorador de Árbol",
842843
"UV": "UV",
843844
"Validation": "Validación",

src/locales/es/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "Después de ejecutar todas las indicaciones"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "Después de ejecutar una indicación"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "Verificar actualizaciones automáticamente"
410
},

src/locales/fr/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "Config-Serveur",
839839
"Settings": "Paramètres",
840840
"Sidebar": "Barre Latérale",
841+
"SoundNotification": "Notification Sonore",
841842
"Tree Explorer": "Explorateur d'Arbre",
842843
"UV": "UV",
843844
"Validation": "Validation",

src/locales/fr/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "Après avoir exécuté toutes les invites"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "Après avoir exécuté une invite"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "Vérifier automatiquement les mises à jour"
410
},

src/locales/ja/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "サーバー設定",
839839
"Settings": "設定",
840840
"Sidebar": "サイドバー",
841+
"SoundNotification": "サウンド通知",
841842
"Tree Explorer": "ツリーエクスプローラー",
842843
"UV": "UV",
843844
"Validation": "検証",

src/locales/ja/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "全てのプロンプト実行後"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "プロンプト実行後"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "自動的に更新を確認する"
410
},

src/locales/ko/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "서버 구성",
839839
"Settings": "설정",
840840
"Sidebar": "사이드바",
841+
"SoundNotification": "소리 알림",
841842
"Tree Explorer": "트리 탐색기",
842843
"UV": "UV",
843844
"Validation": "검증",

src/locales/ko/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "모든 프롬프트를 실행한 후"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "프롬프트를 실행한 후"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "자동 업데이트 확인"
410
},

src/locales/ru/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "Настройки сервера",
839839
"Settings": "Настройки",
840840
"Sidebar": "Боковая панель",
841+
"SoundNotification": "Звуковое оповещение",
841842
"Tree Explorer": "Дерево проводника",
842843
"UV": "UV",
843844
"Validation": "Валидация",

src/locales/ru/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"Comfy_SoundNotification_AfterAllPrompts": {
3+
"name": "после выполнения всех подсказок"
4+
},
5+
"Comfy_SoundNotification_AfterOnePrompt": {
6+
"name": "после выполнения приглашения"
7+
},
28
"Comfy-Desktop_AutoUpdate": {
39
"name": "Автоматически проверять обновления"
410
},

src/locales/zh/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
"Server-Config": "服务器配置",
839839
"Settings": "设置",
840840
"Sidebar": "侧边栏",
841+
"SoundNotification": "声音通知",
841842
"Tree Explorer": "树形浏览器",
842843
"UV": "UV",
843844
"Validation": "验证",

0 commit comments

Comments
 (0)