Felo API PlatformFelo API Platform

コンテンツ

YouTube 動画を公開できる記事に変える

タイムスタンプ付きの文字起こしを取得し、読みやすいブロックに整え、自分で管理するモデルで構成と下書きを作り、レビュー用に LiveDoc へ残します。

所要時間25 分レベル中級更新日2026-10-29
対象コンテンツチームニュースレター執筆者動画・ポッドキャスト編集者

プロンプトをコピー

角括弧の項目を置き換えて、Claude Code、Codex、ターミナルにアクセスできる AI に貼り付けてください。Felo スキルをインストールし、クレジットを使う前に確認し、ワークフローを実行します。

この動画を公開可能な記事にしてください: [YouTube URL または動画 ID]。

読者: [読者]。トーン: [媒体スタイル]。目標文字数: [800〜1200語]、言語: [言語]。
出典の扱い: 動画タイトル、チャンネル、URL を保持してください。引用は短い部分に限り、タイムスタンプを付けてください。

以下を作成してください。
1. 作業用タイトル。
2. スタンドファースト(リード文)。
3. 短い段落で構成したセクション。
4. タイムスタンプ付きの引用を2〜3個。
5. 動画が扱わなかったこと。
6. 動画とリンク先ページを含む出典一覧。

ルール:
- 文字起こし全文を再現しないでください。要約し、短く引用してください。
- 動画からの事実の主張にはタイムスタンプを、リンク先ページからの主張には URL を付けてください。
- 確認できなかったことは「未検証」と明記してください。
- 文字起こし取得やページ抽出でクレジットを消費する前に確認してください。
- 公開、予約、送信はしないでください。
- 結果を ./video-article.md に書き、チャットで要約してください。

コピー内容にはインストール手順と安全ルールも含まれます。

完成するもの

実行時の出力例です。リアルタイム生成ではありません。

記事の例(抜粋)

40分のエージェント講演が実際に語ったこと

スタンドファースト

デモは印象的だったが、役に立つ部分は失敗時の処理だった。

誰もが引用した主張

> 「エージェントが賢くなったのではない。予算なしのリトライをやめさせただけだ」 — [12:40]

動画が扱わなかったこと

成功タスクあたりのコストと、取得したソースが間違っていたときに何が起きるか。

出典

  • 動画: https://www.youtube.com/watch?v=...
  • リンクされたベンチマーク: https://example.com/benchmark

実際の呼び出し

開発者向け:同じワークフローを実行順に並べたコピー可能なコード。

実際の API 呼び出しを表示
  1. タイムスタンプ付き文字起こしを取る

    YouTube Subtitling で対象言語の字幕を取得し、各行の開始時間と長さを残します。

    article.ts
    const BASE = "https://openapi.felo.ai";
    const headers = {
      Authorization: `Bearer ${process.env.FELO_API_KEY}`,
      "Content-Type": "application/json",
    };
    
    async function felo<T>(path: string, body?: unknown): Promise<T> {
      const res = await fetch(`${BASE}${path}`, {
        method: body ? "POST" : "GET",
        headers,
        body: body ? JSON.stringify(body) : undefined,
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<T>;
    }
    
    type Transcript = {
      data: {
        title: string;
        contents: { text: string; start: number; duration: number }[];
      };
    };
    
    export async function fetchTranscript(videoId: string, language = "en") {
      const query = new URLSearchParams({
        video_code: videoId,
        language,
        with_time: "true",
      });
      const { data } = await felo<Transcript>(`/v2/youtube/subtitling?${query}`);
      if (data.contents.length === 0) throw new Error("This video has no subtitles");
      return data;
    }

    出力例

    {
      "title": "How we rebuilt onboarding",
      "contents": [
        { "text": "Welcome back to the channel.", "start": 0.32, "duration": 4.1 }
      ]
    }
  2. 読みやすいブロックに整える

    テーマごとに文字起こしを分割し、口癖のフィラーを除き、タイムスタンプは残します。

    article.ts
    const toClock = (seconds: number) => {
      const minutes = Math.floor(seconds / 60);
      const rest = Math.floor(seconds % 60);
      return `${String(minutes).padStart(2, "0")}:${String(rest).padStart(2, "0")}`;
    };
    
    export function toBlocks(
      contents: Transcript["data"]["contents"],
      window = 60,
    ) {
      const grouped = new Map<number, string[]>();
      for (const line of contents) {
        const bucket = Math.floor(line.start / window) * window;
        grouped.set(bucket, [...(grouped.get(bucket) ?? []), line.text.trim()]);
      }
      return [...grouped]
        .map(([start, lines]) => `[${toClock(start)}] ${lines.join(" ")}`)
        .join("\n\n");
    }

    出力例

    [00:00] Welcome back to the channel. Today we are talking about onboarding.
    
    [01:00] The first thing we changed was the welcome screen.
  3. 動画が参照する出典を取得する

    Web Fetch で動画内で名前が出たページを読み、リンクと事実を補います。

    article.ts
    type ExtractData = { data: { content: string } };
    
    export async function fetchSources(urls: string[]) {
      return Promise.all(
        urls.slice(0, 5).map(async (url) => {
          const page = await felo<ExtractData>("/v2/web/extract", {
            url,
            output_format: "markdown",
            with_readability: true,
          });
          return { url, content: page.data.content };
        }),
      );
    }

    出力例

    [
      {
        "url": "https://example.com/reference",
        "content": "# Reference\n\nExtracted page text…"
      }
    ]
  4. 構成を書いてから下書きする

    モデル API で先に構成を作り、構成に沿って記事を書き、短く引用してタイムスタンプを付けます。

    article.ts
    const MODEL_API = "https://openapi.felo.ai/api/v1";
    
    type Completion = {
      choices: { message: { content: string } }[];
      usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
    };
    
    async function complete(model: string, prompt: string): Promise<Completion> {
      const res = await fetch(`${MODEL_API}/chat/completions`, {
        method: "POST",
        headers,
        body: JSON.stringify({ model, messages: [{ role: "user", content: prompt }] }),
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<Completion>;
    }
    
    export async function draftArticle(title: string, transcript: string) {
      const outline = await complete(
        "claude-haiku-5-5",
        "Outline a short article from this transcript. Return only headings.\n\n" + transcript,
      );
      const article = await complete(
        "claude-sonnet-5-5",
        `Write the article "${title}" from the transcript. Follow the outline and keep [mm:ss] on direct quotes.\n\nOutline:\n${outline.choices[0].message.content}\n\nTranscript:\n${transcript}`,
      );
      return {
        outline: outline.choices[0].message.content,
        article: article.choices[0].message.content,
        usage: article.usage,
      };
    }

    出力例

    {
      "outline": "1. The problem\n2. What changed\n3. What we learned",
      "article": "## The problem\n\nWhen we…",
      "usage": { "prompt_tokens": 4120, "completion_tokens": 640, "total_tokens": 4760 }
    }
  5. LiveDoc に置いてレビューを待つ

    下書きとタイムスタンプ付き引用を LiveDoc に保存し、編集者に修正と承認を依頼します。

    article.ts
    type LiveDocData = { data: { short_id: string } };
    type ResourceData = { data: { id: string } };
    
    export async function saveDraft(
      title: string,
      result: { outline: string; article: string },
    ) {
      const doc = await felo<LiveDocData>("/v2/livedocs", {
        name: `Article draft: ${title}`,
        description: "Draft generated from a video transcript",
      });
    
      await felo<ResourceData>(`/v2/livedocs/${doc.data.short_id}/resources/doc`, {
        title: "Draft",
        content: result.article,
      });
    
      await felo<ResourceData>(`/v2/livedocs/${doc.data.short_id}/resources/doc`, {
        title: "Outline",
        content: result.outline,
      });
    
      return doc.data.short_id;
    }

    出力例

    { "short_id": "PvyKouzJirXjFdst4uKRK3" }

含まれるもの

  • タイムスタンプ付き YouTube 文字起こし
  • 動画が参照するページの Markdown
  • モデル API が作る構成と下書き
  • 下書きを保存し編集者がレビューする LiveDoc

やらないこと

  • 文字起こし全体の転載はせず、短い引用と要約に留める
  • 動画には既存の字幕が必要
  • 再公開前に著作権と引用範囲を確認する
  • モデルは構成と草稿のみ担当し、最終判断は編集者
  • 自動公開や他言語への翻訳はしない

よくある質問

動画に字幕は必要ですか?

必要です。ワークフローは字幕から始まります。字幕がない場合は推測せず停止します。

ポッドキャストも記事にできますか?

このワークフローは YouTube 向けです。ポッドキャストは先に文字起こしを用意し、同じ執筆ルールを使います。

別の言語で書けますか?

はい。対象言語を指定します。引用は原文のまま残し、必要なら翻訳を添えます。

記事を書くのは誰ですか?

プロンプトを貼り付けた AI agent が下書きを書き、Felo が文字起こし、ページ、レビュー環境を提供します。

文字起こし全体を転載できますか?

いいえ。新しい記事と短い引用のみで、文字起こし全体は複製しません。

1回の費用は?

文字起こしとページ抽出は従量制クレジットです。現在の料金は料金ページにあり、プロンプトは使う前に確認を求めます。

関連ワークフロー

自分の形に変える

同じレシピを、実際の進め方に合わせて調整します。

タイムスタンプ引用だけ作る

記事全体ではなく、確認可能な引用リストだけを出力します。二次創作向けです。

先にニュースレター版を書く

記事を短く口語的なニュースレター版に変えます。

チャンネルをまとめて処理する

各動画で同じ手順を繰り返し、それぞれ LiveDoc を保存します。

このレシピの背景にあるリファレンスと、次に見るべきページ。