10
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?

MastraのWorkflow学習用に、人間に判断させるワークフロー(朗読に使用するVOICEVOXキャラをオーディション形式で選ぶ)を作ります。

作るWorkflow

  1. 実行時に青空文庫の『走れメロス』を取得
  2. VOICEVOXの /speakers APIから話者一覧を取得
  3. LLMが2つの観点で朗読キャラを提案する
  4. 同じ冒頭文で、それぞれのサンプルWAVを作る
  5. ユーザーがサンプルを聞いて選ぶ
  6. 選ばれなければ、別候補を再提案する
  7. 決定したキャラで全文朗読WAVを分割生成する

提案は contentmeta の2方針として、出力を固定します。

  • pattern1: 本文の内容から選ぶ
  • pattern2: 作品の評価や教材性など、メタ情報から選ぶ

たとえばpattern1では「緊迫感、友情、メロスの人物像、男性的な声質、叙事性」などを見ます。pattern2では「日本の教材としての定番性、信実の物語、パロディにもされる認知度」などを見ます。

Mastraでのworkflow実装方法

Mastraでは処理をStepとして分けます。

const voiceWorkflow = createWorkflow({
  id: 'hashire-melos-audition-workflow',
  inputSchema: workflowInputSchema,
  outputSchema,
})
  .then(loadSourceStep)
  .then(loadVoiceCatalogStep)
  .then(researchMetaStep)
  .then(prepareAuditionStep)
  .then(auditionStep)
  .then(synthesizeFullStep)
  .commit()

人間の判断を仰ぐauditionStepでは、まずLLMが2つの提案を作り、VOICEVOXでサンプルを生成します。

サンプルWAVは候補ごとの違いを比較しやすいよう、どちらも同じ冒頭文を読み上げます。

LLMには、Agent側の固定指示と、実行時に組み立てるpromptの2つを渡します。

instructions: `
あなたは日本語朗読のキャスティングディレクターです。
太宰治「走れメロス」をVOICEVOXで朗読するため、候補キャラクターを選びます。

必ず2つの提案を作ります。
- pattern1/content: 作品本文の概要、語り口、登場人物、緊張感、感情曲線から声を選ぶ
- pattern2/meta: 作品の評価、教材性、信実・友情・パロディ性などのメタ情報から声を選ぶ
`
const prompt = `
作品: ${inputData.title} / ${inputData.author}

本文冒頭:
${inputData.fullText.slice(0, 1800)}

メタ情報:
${inputData.metaResearch}

VOICEVOX候補:
${compactCatalog(availableStyles.slice(0, 40))}

rejectedStyleIds:
${JSON.stringify(rejectedStyleIds)}

pattern1/content と pattern2/meta の2案を返してください。
`

その後、Workflowをsuspendします。

const audition = await createAuditionSet(inputData, rejectedStyleIds)

return await suspend({
  message:
    '2つの提案とサンプルWAVを確認してください。pattern1 / pattern2 / none のいずれかでresumeします。',
  audition,
})

この時点でWorkflowは停止し、ユーザーの入力を待ちます

[pattern1: 本文内容から選ぶ]
キャラ: 青山龍星 / ノーマル (styleId=13)
理由: メロスの力強さと物語の重厚さに合うため
サンプル: output/audition-attempt-1-.../pattern1-13.wav

[pattern2: メタ評価から選ぶ]
キャラ: 春日部つむぎ / ノーマル (styleId=8)
理由: 教材として聞きやすく、親しみやすさがあるため
サンプル: output/audition-attempt-1-.../pattern2-8.wav

選択してください (1=pattern1 / 2=pattern2 / n=どちらでもない):

選ばれたらresumeDataとしてWorkflowに戻します。

result = await run.resume({
  step: auditionStep,
  resumeData: {
    choice,
    selectedProposal: selectedProposalFor(choice, audition),
    rejectedStyleIds,
  },
})

pattern1またはpattern2なら、候補が確定して次の全文朗読ファイル作成へ進みます。

noneなら、現在の2候補をrejectedStyleIdsに入れて、同じauditionStep内でもう一度候補を作ります。LLMの構造化出力に失敗した場合は、フォールバック提案で継続します。

「人間が選んだら進む」「納得しなければ再提案してまた止まる」という流れを、Workflowの状態として扱えます。

実際に出てきたもの

[pattern1: 本文内容から選ぶ]
キャラ: 玄野武宏 / ノーマル (styleId=11)
理由: 主人公メロスが激怒し、行動にでるための声質は強い意志を示す必要があり、玄野武宏の正常な声質を使うことで、その意気込んでいる気持ちを表現できる。

[pattern2: メタ評価から選ぶ]
キャラ: 四国めたん / ツンツン (styleId=6)
理由: 王が自分の疑心暗鬼を正当化する場面で、緊張感のある声は王の威圧と自負を強調できる。

pattern1が無難かなぁ

理由に関してはそれらしいですが、VOICEVOXのキャラのメタ情報を整備していないのでずんだもんのほのぼのした声が頻繁に登場します。
現状の調整は行っていないため、場面ごとの感情ディレクションを入れるなどでさらに改善できそうです。

10
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
10
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?