From be338c2de0095dd9fcd6b1cda37ade41837206c3 Mon Sep 17 00:00:00 2001 From: c0dev0id Date: Wed, 24 Jun 2026 18:52:26 +0200 Subject: [PATCH] Add audiowidget endpoint: Blueprint renders audiowidget.tmpl, PaneCP fetches it on synthesis completion --- __init__.py | 12 ++++++++ static/api.js | 9 ++++++ static/components/PaneCP.js | 32 ++++++++++++--------- templates/vue3_neusik/audiowidget.tmpl.stub | 18 ++++++++++++ templates/vue3_neusik/index.html | 5 ++-- 5 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 templates/vue3_neusik/audiowidget.tmpl.stub diff --git a/__init__.py b/__init__.py index 3b3084a..69a3984 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,5 @@ from flask import Blueprint, render_template, request +from jinja2 import TemplateNotFound blueprint = Blueprint( 'vue3_neusik', @@ -14,3 +15,14 @@ def index(): 'vue3_neusik/index.html', import_on_load='true' if request.args.get('import') == '1' else 'false', ) + +@blueprint.route('/audiowidget', methods=['GET']) +def audiowidget(): + try: + return render_template( + 'vue3_neusik/audiowidget.tmpl', + result_url=request.args.get('result_url', ''), + errors=request.args.get('errors', ''), + ) + except TemplateNotFound: + return '', 204 diff --git a/static/api.js b/static/api.js index d0aeaf0..0ff49da 100644 --- a/static/api.js +++ b/static/api.js @@ -44,3 +44,12 @@ export async function fetchStatus(credentials) { if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); return res.json(); } + +export async function fetchAudioWidget(resultUrl, errors) { + const params = new URLSearchParams(); + if (resultUrl) params.set('result_url', resultUrl); + if (errors) params.set('errors', errors); + const res = await fetch(`${U.audiowidget}?${params}`); + if (!res.ok || res.status === 204) return ''; + return res.text(); +} diff --git a/static/components/PaneCP.js b/static/components/PaneCP.js index 65649f0..f1e1670 100644 --- a/static/components/PaneCP.js +++ b/static/components/PaneCP.js @@ -1,5 +1,5 @@ -import { h, ref } from 'vue'; -import { fetchScoreText, putScoreText, URLS } from '../api.js'; +import { h, ref, watch } from 'vue'; +import { fetchScoreText, putScoreText, fetchAudioWidget, URLS } from '../api.js'; import { patchScore } from '../exporter.js'; import { StatusPoller } from './StatusPoller.js'; @@ -40,6 +40,18 @@ export const PaneCP = { setup(props) { const exporting = ref(false); const exportError = ref(''); + const audioWidgetHtml = ref(''); + + watch( + () => props.store.synthesisStatus, + async (s) => { + if (!s?.frozen) { audioWidgetHtml.value = ''; return; } + audioWidgetHtml.value = await fetchAudioWidget( + s.file_accomplished ? URLS.result : null, + s.errors ?? null, + ); + }, + ); async function doExport() { exportError.value = ''; @@ -118,18 +130,10 @@ export const PaneCP = { store.synthesisStatus && !store.synthesisStatus.frozen ? h(StatusPoller, { store }) : null, - // Synthesis error - store.synthesisStatus?.frozen && store.synthesisStatus?.errors - ? h('div', { class: 'se-error', style: 'margin-top:0.5rem' }, - store.synthesisStatus.errors) : null, - - // Audio result - store.synthesisStatus?.file_accomplished - ? h('audio', { - controls: true, - src: URLS.result, - style: 'display:block;width:100%;margin-top:0.5rem', - }) : null, + // Audio widget (rendered server-side from audiowidget.tmpl) + audioWidgetHtml.value + ? h('div', { innerHTML: audioWidgetHtml.value, style: 'margin-top:0.5rem' }) + : null, ]); }; }, diff --git a/templates/vue3_neusik/audiowidget.tmpl.stub b/templates/vue3_neusik/audiowidget.tmpl.stub new file mode 100644 index 0000000..1ff33ed --- /dev/null +++ b/templates/vue3_neusik/audiowidget.tmpl.stub @@ -0,0 +1,18 @@ +{# audiowidget.tmpl.stub — copy to audiowidget.tmpl in the same directory to activate. + Customise to match your site's look and feel. + + Context variables (passed as query params by the score editor): + result_url – URL of the rendered MP3, or empty string + errors – synthesis error message, or empty string +#} +{% if errors %} +
{{ errors }}
+{% elif result_url %} +
+
Rendered result
+ +
+{% endif %} diff --git a/templates/vue3_neusik/index.html b/templates/vue3_neusik/index.html index c95d7cc..0d22ecf 100644 --- a/templates/vue3_neusik/index.html +++ b/templates/vue3_neusik/index.html @@ -14,8 +14,9 @@ window.NEUSICIAN_URLS = { astlog: "{{ url_for('astlog') }}", score: "{{ url_for('score') }}", status: "{{ url_for('statusjson') }}", - result: "{{ url_for('send_audio_generated') }}", - submit: "{{ url_for('public-yaml-acceptor') }}" + result: "{{ url_for('send_audio_generated') }}", + submit: "{{ url_for('public-yaml-acceptor') }}", + audiowidget: "{{ url_for('vue3_neusik.audiowidget') }}" };