0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

物語から歌詞を組み立てる:パーソナライズ曲ギフトのプロンプト設計メモ

0
Posted at

記念日や誕生日に「棚から買えるものではない」贈り物を探すと、体験設計が難しいことに気づきます。写真やメッセージカードは手軽ですが、相手の名前や二人だけのエピソードを繰り返し聴ける形に残すには、生成パイプライン側の制約整理が必要です。ここでは公開されている日本語の説明をもとに、Once Song のような「質問→曲」フローを実装するときの設計メモをまとめます。コードはすべて説明用のサンプルであり、プロダクトのソースではありません。

oncesong-ja-1.jpg

プロダクトから見える入出力

日本語版の流れはおおむね次の4段です。

  1. 贈る相手・シーン・残したい思い出を案内に沿って答える
  2. ムード・ジャンル・歌声を選ぶ
  3. まず自分だけで試聴する(非公開プレビュー)
  4. フル楽曲をアンロックして贈り物として残す

公開コピーにある「サビに名前を織り込む」「テンプレの穴埋めではない」「最短30分」などは、実装上は 必須スロット(名前など)と自由記述スロット(エピソード)を分け、後段の歌詞・作曲モデルへ構造化して渡す 問題に落ちます。ここを曖昧なまま長い自然文プロンプトに連結すると、固有名詞の欠落やトーンのぶれが増えます。

回答を構造化する

フォームをそのまま連結する前に、スキーマを固定します。必須項目と任意項目を型で区別しておくと、バリデーションと再生成の条件が書きやすくなります。

type SongBrief = {
  recipientName: string;          // サビ必須
  occasion: 'anniversary' | 'birthday' | 'wedding' | 'proposal' | 'memorial' | 'other';
  memories: string[];             // 短文のエピソード(2〜6件)
  insideJokes?: string[];
  mood: string;                   // 例: warm / nostalgic
  genre: string;                  // 例: acoustic / pop
  voice: 'female' | 'male' | 'neutral';
  language: 'ja' | 'en' | string;
};

function toLyricPrompt(b: SongBrief): string {
  const mem = b.memories.map((m, i) => `${i + 1}. ${m}`).join('\n');
  return [
    `Language: ${b.language}`,
    `Recipient name (must appear in chorus): ${b.recipientName}`,
    `Occasion: ${b.occasion}`,
    `Mood: ${b.mood}; Genre: ${b.genre}; Voice: ${b.voice}`,
    'Write original lyrics (no template fill-in). Use memories concretely:',
    mem,
    'Structure: verse1 / pre-chorus / chorus / verse2 / chorus / bridge / final chorus',
  ].join('\n');
}

ポイントは 名前を「推奨」ではなく契約にする ことです。生成後にサビ文字列を検査し、名前が含まれなければ再生成か人手レビューに回すと、ギフト体験の失敗率が下がります。エピソードは「短い具体」を複数渡す方が、長い独白を1本渡すより歌詞に残りやすい、という経験則もあります。

試聴とアンロックを状態で分ける

oncesong-ja-2.jpg

プレビューは「自分だけで確認」、フル版は「贈り物として残す」——公開フローそのものが課金境界です。API設計では次のように状態を分けるのが素直です。

type SongJob = {
  id: string;
  brief: SongBrief;
  status: 'queued' | 'preview_ready' | 'unlocked' | 'failed';
  previewUrl?: string;  // 短尺 or 透かし
  fullUrl?: string;     // unlock 後のみ
};

function canDownloadFull(job: SongJob) {
  // クライアントの「再生できた」は認可に使わない
  return job.status === 'unlocked';
}

プレビューURLを知っていてもフル音源が取れないよう、署名付きURLの権限をサーバ側で分離します。ギフト用途では、完成前に相手へリンクが漏れないことも重要です。キューの待ち時間(「最短30分」をうたうなら)は、ジョブのSLO監視とユーザー向けの進捗表示をセットで設計します。失敗時は「同じ Brief で再試行できるか/クレジットを戻すか」を先に決めておくとサポートが楽です。

品質チェックの最低ライン

生成系プロダクトでは、モデル出力をそのまま返さず、ゲートを通すのが定石です。

  • サビに recipientName が含まれるか(表記ゆれを正規化してから判定)
  • 禁止トピックや過度にセンシティブな記述のフィルタ
  • ジャンル/ムード指定との粗い一致(タグ不一致なら再生成)
  • 歌詞の言語が指定言語と一致しているか
  • 生成時間のSLO(キュー滞留・ワーカー死活)
function normalizeName(s: string) {
  return s.normalize('NFKC').toLowerCase().replace(/\s+/g, '');
}

function chorusContainsName(lyrics: string, name: string) {
  // サンプル: 最初の [Chorus] ブロックだけ見る
  const m = lyrics.match(/\[Chorus\]([\s\S]*?)(\[|$)/i);
  const chorus = m?.[1] ?? lyrics;
  return normalizeName(chorus).includes(normalizeName(name));
}

oncesong-ja-3.jpg

ゲートを通らなかった場合は、同じ Brief を保ったまま「歌詞のみ再生成」「歌声のみ差し替え」など、段を分けてリトライできるとコストが下がります。全部を最初からやり直す必要はありません。

フロントの役割とやらないこと

  • やる: Brief の入力支援、プレビュー再生、アンロック後のダウンロード、相手に渡す前の最終確認
  • やらない: ブラウザだけでフル音源URLを推測する、プレビューをSNSに先出しする導線を黙って置く、必須スロット未入力のまま生成APIを叩く

「まずは自分だけで聴く」という公開コピーは、実装ではプレビュー権限と共有UIの初期状態にそのまま写ります。

キューとワーカーの分け方

歌詞生成・音声合成・マスタリングを1リクエストで同期実行すると、タイムアウトと再試行がつらくなります。公開の「最短30分」を守るなら、少なくとも次の段に分けた方が安全です。

  1. Brief 受理(同期)→ queued
  2. 歌詞生成(非同期)→ ゲート通過で次へ
  3. 音声合成(非同期)→ preview_ready
  4. アンロック後にフル音源を確定 → unlocked

各段で失敗理由をコード化し、ユーザー向け文言と内部ログを分けます。「もう一度試す」がどの段から再開できるかを UI に出すと、サポート問い合わせが減ります。ワーカーは冪等キー(jobId + stage)を持ち、二重実行で二重課金しないようにします。

多言語とギフト文脈

Once Song は多言語サイトとして公開されていますが、1曲のなかで言語が混ざるとギフト体験が壊れやすいです。Brief の language を歌詞・読み上げ・メール文面のすべてに伝播させ、プレビュー画面のUI言語と曲の言語が食い違う場合は明示します。記念日・結婚式・追悼など occasion ごとに禁止表現リストを少し変えるのも有効です(祝いの場に重い表現が混ざる事故を防ぐ)。

まとめ

パーソナライズ曲は「いい感じの歌詞を一発で出す」より、必須スロットの保証・試聴とフルの権限分離・再生成ループ の方が体験を左右します。質問の順番、ムード選択、非公開プレビューの見せ方は Once Song の公開ページで確認できます。物語を音にするプロダクトでは、LLMの出力そのものより、フォーム設計と状態機械の方が長く効いてきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?