Felo API PlatformFelo API Platform

内容

把 YouTube 视频变成一篇可发布的文章

拉取带时间戳的转录,整理成可读的段落,用你控制的模型列大纲并写初稿,再把结果留在 LiveDoc 里等编辑 review。

构建时间25 分钟难度进阶更新于2026-10-29
适合谁内容团队Newsletter 作者视频与播客编辑

复制 prompt

把方括号里的字段替换掉,然后粘贴到 Claude Code、Codex 或任何能访问终端的 AI。它会安装 Felo skill、在花额度前询问,并执行这套 workflow。

把这条视频变成一篇可发布的文章:[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

实际调用

给开发者:同一套 workflow 的可复制代码,按执行顺序排列。

展开实际 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

不做什么

  • 不能直接复用完整转录,只能短引并改写
  • 视频需要已有字幕
  • 转载前必须确认版权和引用范围
  • 模型只负责大纲和草稿,最终判断在编辑
  • 不自动发布或翻译成其他语言

常见问题

视频需要字幕吗?

需要。workflow 从字幕开始;没有字幕时会停下,而不是猜视频说了什么。

可以把播客变成文章吗?

这套 workflow 针对 YouTube;播客需要先准备转录,再走同样的写作规则。

可以写成其他语言吗?

可以。指定目标语言;引语保留原文,需要时附翻译。

文章是谁写的?

你粘贴 prompt 的 AI agent 写初稿,Felo 提供转录、页面和 review 工作区。

可以转载完整转录吗?

不可以。workflow 只做新文章和短引,不复制完整转录。

一次要花多少?

转录和页面抽取按用量计费;当前费率在价格页面,prompt 会先请求确认。

相关 workflow

改成你的版本

同一套配方,按你实际的交付方式调整。

只做时间戳引语

不写整篇,只输出可核对的引语清单,适合二次创作。

先写 newsletter 版本

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

批量处理一个频道

对每个视频重复同一套步骤,并各自保存 LiveDoc。

这套配方背后的参考页面,以及下一步可以看什么。