feat: send song requests to Hermes via webhook
- Add Hermes webhook settings form in /admin/settings (URL + HMAC secret) - Add /admin/request/<id>/send-to-hermes action - POST request data to Hermes with V2 HMAC signature and callback URL - Hermes can POST the generated MusicGPT prompt back to /api/prompt/<id> - Add test button, update README workflow, bump version to 0.9.0
This commit is contained in:
parent
3c99378044
commit
2f5050b29f
6 changed files with 199 additions and 4 deletions
72
app.py
72
app.py
|
|
@ -77,6 +77,7 @@ from helpers import (
|
|||
download_album_cover,
|
||||
process_stems_to_gokapi,
|
||||
get_ntfy_config, send_ntfy,
|
||||
get_hermes_webhook_config, set_hermes_webhook_config, send_hermes_webhook,
|
||||
sign_prompt_callback, verify_prompt_callback, build_prompt_callback_url,
|
||||
send_email, build_signature_images,
|
||||
get_booth_open,
|
||||
|
|
@ -1503,6 +1504,38 @@ def admin_request(rid):
|
|||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route('/admin/request/<int:rid>/send-to-hermes', methods=['POST'])
|
||||
def send_to_hermes(rid):
|
||||
"""
|
||||
Operator action: push the current request data to the configured Hermes webhook.
|
||||
Hermes will generate a MusicGPT prompt and POST it back to the callback URL.
|
||||
"""
|
||||
redir = require_admin()
|
||||
if redir:
|
||||
return redir
|
||||
req = get_request_by_id(rid)
|
||||
if not req:
|
||||
abort(404)
|
||||
if req['status'] not in ('pending', 'revisions_requested'):
|
||||
flash('Request must be pending or awaiting revision to send to Hermes.', 'error')
|
||||
return redirect(url_for('admin_request', rid=rid))
|
||||
|
||||
cfg = get_hermes_webhook_config()
|
||||
if not cfg['url'] or not cfg['secret']:
|
||||
flash('Hermes webhook is not configured. Set URL and secret in /admin/settings.', 'error')
|
||||
return redirect(url_for('admin_request', rid=rid))
|
||||
|
||||
callback_url = build_prompt_callback_url(rid)
|
||||
ok, msg = send_hermes_webhook(rid, req, callback_url=callback_url)
|
||||
if ok:
|
||||
flash(f'Sent to Hermes. {msg}', 'success')
|
||||
else:
|
||||
flash(f'Failed to send to Hermes: {msg}', 'error')
|
||||
return redirect(url_for('admin_request', rid=rid))
|
||||
|
||||
|
||||
@app.route('/admin/request/<int:rid>/delete', methods=['POST'])
|
||||
def admin_delete_request(rid):
|
||||
"""Delete a single request and remove its uploaded MP3 files."""
|
||||
|
|
@ -1850,6 +1883,42 @@ def admin_settings():
|
|||
flash('ntfy notification settings saved.', 'success')
|
||||
return redirect(url_for('admin_settings'))
|
||||
|
||||
elif action == 'save_hermes_webhook':
|
||||
# Update Hermes webhook URL and secret from the settings form.
|
||||
webhook_url = request.form.get('hermes_webhook_url', '').strip().rstrip('/')
|
||||
webhook_secret = request.form.get('hermes_webhook_secret', '').strip()
|
||||
set_hermes_webhook_config(webhook_url, webhook_secret)
|
||||
flash('Hermes webhook settings saved.', 'success')
|
||||
return redirect(url_for('admin_settings'))
|
||||
|
||||
elif action == 'send_test_hermes_webhook':
|
||||
# Send a test request to the configured Hermes webhook.
|
||||
cfg = get_hermes_webhook_config()
|
||||
if not cfg['url'] or not cfg['secret']:
|
||||
flash('Configure Hermes webhook URL and secret first.', 'error')
|
||||
return redirect(url_for('admin_settings'))
|
||||
ok, msg = send_hermes_webhook(0, {
|
||||
'email': 'test@example.com',
|
||||
'name': 'Test Customer',
|
||||
'pronouns': 'They/Them/Their',
|
||||
'hobbies': 'testing',
|
||||
'notable_facts': 'none',
|
||||
'style_genre': "1980's, Pop, Funk",
|
||||
'vocal_gender': 'female',
|
||||
'extra_requests': 'Test webhook',
|
||||
'stems_interest': 0,
|
||||
'revision_count': 0,
|
||||
'revision_note': '',
|
||||
'suno_title': '',
|
||||
'suno_style': '',
|
||||
'suno_lyrics': '',
|
||||
})
|
||||
if ok:
|
||||
flash(f'Test Hermes webhook sent. {msg}', 'success')
|
||||
else:
|
||||
flash(f'Test Hermes webhook failed: {msg}', 'error')
|
||||
return redirect(url_for('admin_settings'))
|
||||
|
||||
elif action == 'send_test_ntfy':
|
||||
# Send a test push notification to the configured ntfy topic.
|
||||
ntfy = get_ntfy_config()
|
||||
|
|
@ -1911,6 +1980,7 @@ def admin_settings():
|
|||
musicgpt_api_key_set=bool(get_musicgpt_api_key()),
|
||||
musicgpt_webhook_url=build_musicgpt_webhook_url(),
|
||||
musicgpt_autopoll=runtime_settings.get('musicgpt_autopoll', True),
|
||||
hermes_webhook=get_hermes_webhook_config(),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1967,4 +2037,4 @@ with app.app_context():
|
|||
# If the database path is not yet reachable (e.g. volume not mounted),
|
||||
# defer to the first request or the explicit init-db command.
|
||||
import logging
|
||||
logging.getLogger('app').warning('Startup init_db() failed; database may need manual initialization.', exc_info=True)
|
||||
logging.getLogger('app').warning('Startup init_db() failed; database may need manual initialization.', exc_info=True)
|
||||
Loading…
Add table
Add a link
Reference in a new issue