Single-paste Hermes response with title extraction and copy buttons

This commit is contained in:
Troll (Hermes Agent) 2026-07-31 21:38:38 +00:00
parent 665a7e5655
commit 30732c0b64
3 changed files with 46 additions and 19 deletions

1
app.py
View file

@ -196,6 +196,7 @@ def admin_request(rid):
if action == 'save_prompt':
update_request(rid,
suno_title=request.form.get('suno_title', '').strip(),
suno_style=request.form.get('suno_style', '').strip(),
suno_lyrics=request.form.get('suno_lyrics', '').strip(),
status='prompt_ready'

View file

@ -14,6 +14,7 @@ CREATE TABLE IF NOT EXISTS requests (
style_genre TEXT,
extra_requests TEXT,
status TEXT DEFAULT 'pending',
suno_title TEXT,
suno_style TEXT,
suno_lyrics TEXT,
song_a_path TEXT,

View file

@ -53,25 +53,31 @@ pre{background:#111827;padding:.8rem;border-radius:.5rem;overflow:auto;white-spa
<div class="section">
<h2>1. Generate Suno Prompt</h2>
<button type="button" onclick="copyPromptForHermes()">Copy customer info for Hermes</button>
<p class="copy-hint">Paste the Style block and Lyrics block from Hermes into the boxes below, then click Apply.</p>
<p class="copy-hint">Paste Hermes response into the box below. It will auto-extract Title, Style, and Lyrics.</p>
<label for="pasted_style">Paste Style block here</label>
<textarea id="pasted_style" rows="6" placeholder="Everything under 'Style:'"></textarea>
<label for="pasted_lyrics">Paste Lyrics block here</label>
<textarea id="pasted_lyrics" rows="10" placeholder="Everything under 'Lyrics:'"></textarea>
<label for="hermes_response">Paste Hermes response here</label>
<textarea id="hermes_response" rows="14" placeholder="Title: ...\nStyle: ...\nLyrics: ..."></textarea>
<div class="actions">
<button type="button" class="secondary" onclick="applyPastedBlocks()">Apply to fields</button>
<button type="button" class="secondary" onclick="extractHermesResponse()">Extract Title / Style / Lyrics</button>
</div>
<form method="POST">
<input type="hidden" name="action" value="save_prompt">
<label for="suno_title">Suggested Title</label>
<input type="text" id="suno_title" name="suno_title" value="{{ req.suno_title or '' }}" readonly>
<label for="suno_style">Suno Style</label>
<textarea id="suno_style" name="suno_style">{{ req.suno_style or '' }}</textarea>
<label for="suno_lyrics">Suno Lyrics (with metatags)</label>
<textarea id="suno_lyrics" name="suno_lyrics" rows="12">{{ req.suno_lyrics or '' }}</textarea>
<div class="actions">
<button type="button" class="secondary" onclick="copyToClipboard('suno_title', 'Title')">Copy Title</button>
<button type="button" class="secondary" onclick="copyToClipboard('suno_style', 'Style')">Copy Style</button>
<button type="button" class="secondary" onclick="copyToClipboard('suno_lyrics', 'Lyrics')">Copy Lyrics</button>
<button type="submit">Save Prompt</button>
</div>
</form>
@ -127,24 +133,43 @@ function copyPromptForHermes() {
style_genre: {{ req.style_genre | tojson }},
extra_requests: {{ req.extra_requests | tojson }}
};
const text = `Please write a Suno Custom Mode prompt for this customer.\n\nCustomer data:\nName: ${data.name}\nHobbies: ${data.hobbies || '-'}\nNotable facts: ${data.notable_facts || '-'}\nStyle / genre: ${data.style_genre || '-'}\nExtra requests: ${data.extra_requests || '-'}\n\nReply with exactly this format (no JSON):\n\nStyle:\n[the style description here]\n\nLyrics:\n[the lyrics here, with metatags]`;
navigator.clipboard.writeText(text).then(() => alert("Copied! Paste Hermes response into the Style and Lyrics boxes, then click Apply."));
const text = `Please write a Suno Custom Mode prompt for this customer. Suggest a song title too.\n\nCustomer data:\nName: ${data.name}\nHobbies: ${data.hobbies || '-'}\nNotable facts: ${data.notable_facts || '-'}\nStyle / genre: ${data.style_genre || '-'}\nExtra requests: ${data.extra_requests || '-'}\n\nReply with exactly this format:\n\nTitle: [suggested title]\n\nStyle:\n[the style description here]\n\nLyrics:\n[the lyrics here, with metatags]`;
navigator.clipboard.writeText(text).then(() => alert("Copied! Paste Hermes response into the box above and click Extract."));
}
function applyPastedBlocks() {
const styleBlock = document.getElementById('pasted_style').value.trim();
const lyricsBlock = document.getElementById('pasted_lyrics').value.trim();
if (!styleBlock && !lyricsBlock) {
alert("Paste Style and/or Lyrics first.");
function extractHermesResponse() {
const raw = document.getElementById('hermes_response').value;
if (!raw.trim()) {
alert("Paste Hermes response first.");
return;
}
if (styleBlock) {
document.getElementById('suno_style').value = styleBlock;
const titleMatch = raw.match(/^[\s]*Title:\s*([\s\S]*?)(?=\n\s*Style:|\n\s*Lyrics:|$)/im);
const styleMatch = raw.match(/^[\s]*Style:\s*([\s\S]*?)(?=\n\s*Lyrics:|$)/im);
const lyricsMatch = raw.match(/^[\s]*Lyrics:\s*([\s\S]*?)$/im);
if (titleMatch) {
document.getElementById('suno_title').value = titleMatch[1].trim();
}
if (lyricsBlock) {
document.getElementById('suno_lyrics').value = lyricsBlock;
if (styleMatch) {
document.getElementById('suno_style').value = styleMatch[1].trim();
}
alert("Style and lyrics applied.");
if (lyricsMatch) {
document.getElementById('suno_lyrics').value = lyricsMatch[1].trim();
}
if (!styleMatch && !lyricsMatch) {
alert("Could not find Style or Lyrics sections. Make sure the response uses the exact format.");
} else {
alert("Title, Style, and Lyrics extracted. Use Copy buttons to paste into Suno.");
}
}
function copyToClipboard(elementId, label) {
const el = document.getElementById(elementId);
el.select();
el.setSelectionRange(0, 99999);
navigator.clipboard.writeText(el.value).then(() => alert(label + " copied!"));
}
</script>
</div>