Compare commits

...
2 Commits
Author SHA1 Message Date
Jannik cba6a173e6 chore: user tweaks to system prompts 2026-06-04 12:51:17 +02:00
Jannik 5bc3b6bbcb feat: improve video AI tool links UX and copy prompt on click 2026-06-04 12:49:01 +02:00
2 changed files with 43 additions and 23 deletions
+7 -11
View File
@@ -33,24 +33,20 @@ REQUIRED JSON STRUCTURE:
"video_prompts": [ "video_prompts": [
{ {
"type": "Abstract", "type": "Abstract",
"prompt": "5-second seamless loop, 16:9 aspect ratio. Abstract visuals: particles, fluid colors, geometric shapes, motion graphics. Specify: scene, camera angle, camera movement (slow pan/zoom/static), color palette (2-3 colors only), light source, motion quality. Must loop seamlessly (first frame = last frame). If using reverse playback, only use elements that make physical sense in reverse (e.g. pulsing light, expanding rings — NOT falling rain or rising smoke). Mood must match the song. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur", "prompt": "short seamless loop, 16:9 aspect ratio. Abstract visuals: particles, fluid colors, geometric shapes, motion graphics. Specify: scene, camera angle, camera movement (slow pan/zoom/static), color palette (2-3 colors only), light source, motion quality. Must loop seamlessly (first frame = last frame). If using reverse playback, only use elements that make physical sense in reverse (e.g. pulsing light, expanding rings — NOT falling rain or rising smoke). Mood must match the song. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
"tool_recommendation": "Tool name(s) + one-sentence reason why they suit this prompt"
}, },
{ {
"type": "Cinematic", "type": "Cinematic",
"prompt": "5-second seamless loop, 16:9 aspect ratio. Real-world environment: landscape, weather, architecture, nature. Specify: scene, camera angle, camera movement, color palette (2-3 colors), light source, motion quality. Loopable (first frame = last frame). If elements move (rain, wind, water, fire), they must move in a physically correct direction — do NOT suggest rain or smoke as reversible loops. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur", "prompt": "short seamless loop, 16:9 aspect ratio. Real-world environment: landscape, weather, architecture, nature. Specify: scene, camera angle, camera movement, color palette (2-3 colors), light source, motion quality. Loopable (first frame = last frame). If elements move (rain, wind, water, fire), they must move in a physically correct direction — do NOT suggest rain or smoke as reversible loops. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
"tool_recommendation": "Tool name(s) + one-sentence reason"
}, },
{ {
"type": "Hybrid", "type": "Hybrid",
"prompt": "5-second seamless loop, 16:9 aspect ratio. Blend of real and abstract: e.g. real environment with overlaid light effects, particle overlays on landscape, or a semi-abstract architectural scene. Loopable. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur", "prompt": "short seamless loop, 16:9 aspect ratio. Blend of real and abstract: e.g. real environment with overlaid light effects, particle overlays on landscape, or a semi-abstract architectural scene. Loopable. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
"tool_recommendation": "Tool name(s) + one-sentence reason"
} }
] ]
} }
Keep each video_prompts[].prompt under 900 characters (excluding the Negative line). Keep each video_prompts[].prompt under 900 characters (excluding the Negative line).`,
Recommended video tools (choose the best fit per prompt): {{VIDEO_TOOLS}}. Never recommend Sora.`,
partial: `You are a music production assistant specializing in Suno AI song creation. partial: `You are a music production assistant specializing in Suno AI song creation.
The user has an existing song and wants to regenerate ONE section. Output ONLY The user has an existing song and wants to regenerate ONE section. Output ONLY
@@ -78,8 +74,8 @@ QUALITY CONSTRAINTS:
ABAB rhyme. No references to instruments, genre, or music production. ABAB rhyme. No references to instruments, genre, or music production.
- style: comma-separated, max 120 words, include tempo + BPM range, never - style: comma-separated, max 120 words, include tempo + BPM range, never
name an artist, no "sounds like" phrases. name an artist, no "sounds like" phrases.
- video_prompts: 5-second seamless loops, 16:9. Include the "Negative" line - video_prompts: short seamless loops, 16:9. Include the "Negative" line
inside each prompt. Keep prompts under 900 characters. Recommended tools: {{VIDEO_TOOLS}}. Never recommend Sora. inside each prompt. Keep prompts under 900 characters.
- youtube_description: follow the hook → description → divider → lyrics → - youtube_description: follow the hook → description → divider → lyrics →
divider → CTA → hashtags structure.`, divider → CTA → hashtags structure.`,
style_normal: `You are a Suno style-prompt generator. style_normal: `You are a Suno style-prompt generator.
@@ -157,7 +153,7 @@ function getToolsString() {
export function buildSystemPrompt(req) { export function buildSystemPrompt(req) {
const toolsStr = getToolsString(); const toolsStr = getToolsString();
if (req.section === 'lyrics_partial') { if (req.section === 'lyrics_partial') {
return activePrompts.lyrics_partial; return activePrompts.lyrics_partial;
} }
+36 -12
View File
@@ -11,6 +11,7 @@ import {
} from "../../lib/types"; } from "../../lib/types";
import { useVideoAiLinks } from "../../lib/useVideoAiLinks"; import { useVideoAiLinks } from "../../lib/useVideoAiLinks";
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons"; import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
import { useToast } from "../../lib/toast";
interface VideoPromptsCardProps { interface VideoPromptsCardProps {
prompts: VideoPrompt[]; prompts: VideoPrompt[];
@@ -37,6 +38,36 @@ export function VideoPromptsCard({
const ref = useAutoHeight(current?.prompt ?? "", 120); const ref = useAutoHeight(current?.prompt ?? "", 120);
const { links } = useVideoAiLinks(); const { links } = useVideoAiLinks();
const toast = useToast();
const handleToolClick = async (url: string) => {
if (!current) return;
// Copy the prompt to clipboard (with negative prompt if applicable)
const textToCopy = `Prompt: ${current.prompt}\n\nNegative: ${NEGATIVE_VIDEO_PROMPT}`;
try {
await navigator.clipboard.writeText(textToCopy);
toast.success("Prompt copied to clipboard!");
} catch {
// Fallback
const ta = document.createElement("textarea");
ta.value = textToCopy;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try {
document.execCommand("copy");
toast.success("Prompt copied to clipboard!");
} catch {
toast.error("Failed to copy prompt");
}
document.body.removeChild(ta);
}
// Open the tool in a new tab
window.open(url, "_blank", "noopener,noreferrer");
};
return ( return (
<ResultCard <ResultCard
@@ -103,13 +134,6 @@ export function VideoPromptsCard({
/> />
</div> </div>
<p className="text-sm italic text-fg-muted">
Best for:{" "}
<span className="not-italic text-fg">
{current.tool_recommendation}
</span>
</p>
<div className="mt-1 p-3 rounded-lg bg-bg-hover/40 border border-border"> <div className="mt-1 p-3 rounded-lg bg-bg-hover/40 border border-border">
<p className="text-[11px] uppercase tracking-wider text-fg-muted mb-1"> <p className="text-[11px] uppercase tracking-wider text-fg-muted mb-1">
Negative Negative
@@ -122,16 +146,16 @@ export function VideoPromptsCard({
{links && links.length > 0 && ( {links && links.length > 0 && (
<div className="pt-2 flex flex-wrap gap-2"> <div className="pt-2 flex flex-wrap gap-2">
{links.map((link, i) => ( {links.map((link, i) => (
<a <button
key={i} key={i}
href={link.url} type="button"
target="_blank" onClick={() => handleToolClick(link.url)}
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[11px] font-bold uppercase tracking-wide bg-accent-primary/10 text-accent-primary hover:bg-accent-primary hover:text-white transition-all duration-150 border border-accent-primary/20 hover:border-accent-primary" className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[11px] font-bold uppercase tracking-wide bg-accent-primary/10 text-accent-primary hover:bg-accent-primary hover:text-white transition-all duration-150 border border-accent-primary/20 hover:border-accent-primary"
title={`Copy prompt and open ${link.name}`}
> >
{link.name} {link.name}
<FontAwesomeIcon icon={faExternalLinkAlt} className="w-3 h-3" /> <FontAwesomeIcon icon={faExternalLinkAlt} className="w-3 h-3" />
</a> </button>
))} ))}
</div> </div>
)} )}