feat: improve video AI tool links UX and copy prompt on click
This commit is contained in:
+7
-11
@@ -33,24 +33,20 @@ REQUIRED JSON STRUCTURE:
|
||||
"video_prompts": [
|
||||
{
|
||||
"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",
|
||||
"tool_recommendation": "Tool name(s) + one-sentence reason why they suit this prompt"
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"tool_recommendation": "Tool name(s) + one-sentence reason"
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"tool_recommendation": "Tool name(s) + one-sentence reason"
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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.`,
|
||||
Keep each video_prompts[].prompt under 900 characters (excluding the Negative line).`,
|
||||
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
|
||||
@@ -78,8 +74,8 @@ QUALITY CONSTRAINTS:
|
||||
ABAB rhyme. No references to instruments, genre, or music production.
|
||||
- style: comma-separated, max 120 words, include tempo + BPM range, never
|
||||
name an artist, no "sounds like" phrases.
|
||||
- video_prompts: 5-second seamless loops, 16:9. Include the "Negative" line
|
||||
inside each prompt. Keep prompts under 900 characters. Recommended tools: {{VIDEO_TOOLS}}. Never recommend Sora.
|
||||
- video_prompts: short seamless loops, 16:9. Include the "Negative" line
|
||||
inside each prompt. Keep prompts under 900 characters.
|
||||
- youtube_description: follow the hook → description → divider → lyrics →
|
||||
divider → CTA → hashtags structure.`,
|
||||
style_normal: `You are a Suno style-prompt generator.
|
||||
@@ -157,7 +153,7 @@ function getToolsString() {
|
||||
|
||||
export function buildSystemPrompt(req) {
|
||||
const toolsStr = getToolsString();
|
||||
|
||||
|
||||
if (req.section === 'lyrics_partial') {
|
||||
return activePrompts.lyrics_partial;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "../../lib/types";
|
||||
import { useVideoAiLinks } from "../../lib/useVideoAiLinks";
|
||||
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useToast } from "../../lib/toast";
|
||||
|
||||
interface VideoPromptsCardProps {
|
||||
prompts: VideoPrompt[];
|
||||
@@ -37,6 +38,36 @@ export function VideoPromptsCard({
|
||||
|
||||
const ref = useAutoHeight(current?.prompt ?? "", 120);
|
||||
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 (
|
||||
<ResultCard
|
||||
@@ -103,13 +134,6 @@ export function VideoPromptsCard({
|
||||
/>
|
||||
</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">
|
||||
<p className="text-[11px] uppercase tracking-wider text-fg-muted mb-1">
|
||||
Negative
|
||||
@@ -122,16 +146,16 @@ export function VideoPromptsCard({
|
||||
{links && links.length > 0 && (
|
||||
<div className="pt-2 flex flex-wrap gap-2">
|
||||
{links.map((link, i) => (
|
||||
<a
|
||||
<button
|
||||
key={i}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
type="button"
|
||||
onClick={() => handleToolClick(link.url)}
|
||||
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}
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} className="w-3 h-3" />
|
||||
</a>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user