Felo API PlatformFelo API Platform

內容

把 YouTube 影片變成一篇可發佈的文章

拉取帶時間戳的轉錄,整理成可讀的段落,用你控制的模型列大綱並寫初稿,再把結果留在 LiveDoc 裡等編輯 review。

建置時間25 分鐘難度進階更新於2026-10-29
適合誰內容團隊Newsletter 作者影片與 Podcast 編輯

複製 prompt

把方括號裡的欄位替換掉,然後貼到 Claude Code、Codex 或任何能存取終端機的 AI。它會安裝 Felo skill、在花額度前詢問,並執行這套工作流程。

把這支影片變成一篇可發布的文章:[YouTube URL 或影片 ID]。

讀者:[讀者]。語氣:[媒體風格]。目標長度:[800–1200 字],語言:[語言]。
來源處理:保留影片標題、頻道和 URL。引用最多只取短片段,並附時間戳。

輸出:
1. 工作標題。
2. 導言。
3. 由短段落組成的章節。
4. 兩到三條附時間戳的引文。
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 等 review

    把初稿和時間戳引語存進 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 產生的大綱和初稿
  • 保存初稿、供編輯 review 的 LiveDoc

不做什麼

  • 不能直接複製完整轉錄,只能短引並改寫
  • 影片需要已有字幕
  • 轉載前必須確認版權和引用範圍
  • 模型只負責大綱和草稿,最終判斷在編輯
  • 不自動發佈或翻譯成其他語言

常見問題

影片需要字幕嗎?

需要。工作流程從字幕開始;沒有字幕時會停下,而不是猜影片說了什麼。

可以把 Podcast 變成文章嗎?

這套工作流程針對 YouTube;Podcast 需要先準備轉錄,再走同樣的寫作規則。

可以寫成其他語言嗎?

可以。指定目標語言;引語保留原文,需要時附翻譯。

文章是誰寫的?

你貼上 prompt 的 AI agent 寫初稿,Felo 提供轉錄、頁面和 review 工作區。

可以轉載完整轉錄嗎?

不可以。工作流程只做新文章和短引,不複製完整轉錄。

一次要花多少?

轉錄和頁面擷取按用量計費;目前費率在價格頁面,prompt 會先請求確認。

相關工作流程

改成你的版本

同一套配方,依你實際的交付方式調整。

只做時間戳引語

不寫整篇,只輸出可核對的引語清單,適合二次創作。

先寫 newsletter 版本

把文章改成更短、更口語的 newsletter 版本。

批量處理一個頻道

對每個影片重複同一套步驟,並各自保存 LiveDoc。

這套配方背後的參考頁面,以及下一步可以看什麼。