Felo API PlatformFelo API Platform

Nội dung

Biến video YouTube thành bài viết có thể xuất bản

Lấy bản ghi có timestamp, chia thành đoạn dễ đọc, lập dàn ý và bản nháp bằng model bạn kiểm soát, rồi để kết quả trong LiveDoc chờ biên tập.

Thời gian25 phútMứcTrung cấpCập nhật2026-10-29
Dành cho aiNhóm nội dungNgười viết newsletterBiên tập video và podcast

Sao chép prompt

Thay các trường trong ngoặc vuông rồi dán vào Claude Code, Codex hoặc AI có quyền truy cập terminal. Nó cài skill Felo, hỏi trước khi dùng credit và chạy quy trình.

Chuyển video này thành bài viết có thể công bố: [URL YouTube hoặc ID video].

Độc giả: [người đọc]. Giọng điệu: [phong cách ấn phẩm]. Độ dài mục tiêu: [800–1200 từ] bằng [ngôn ngữ].
Xử lý nguồn: giữ tiêu đề, kênh và URL video. Chỉ trích đoạn ngắn, kèm mốc thời gian.

Tạo:
1. Tiêu đề tạm.
2. Đoạn mở đầu.
3. Các mục với đoạn ngắn.
4. Hai hoặc ba trích dẫn có mốc thời gian.
5. Những gì video không bao phủ.
6. Danh sách nguồn gồm video và các trang được liên kết.

Quy tắc:
- Không sao chép toàn bộ bản ghi. Tóm tắt và trích ngắn.
- Mọi nhận định thực tế từ video cần mốc thời gian; nhận định từ trang liên kết cần URL.
- Ghi “Chưa xác minh” cho mọi điều bạn không kiểm chứng được.
- Hỏi trước khi tiêu tín dụng cho bản ghi hoặc trích xuất trang.
- Không công bố, lên lịch hay gửi gì.
- Ghi kết quả vào ./video-article.md và tóm tắt trong chat.

Bản sao cũng gồm các bước cài đặt và quy tắc an toàn.

Bạn nhận được gì

Kết quả mẫu của một lần chạy. Không phải tạo trực tiếp.

Ví dụ bài viết (trích)

Bài nói 40 phút về agent thực sự nói gì

Đoạn mở

Bản demo ấn tượng; phần hữu ích là xử lý lỗi.

Tuyên bố mọi người trích

> “Agent không thông minh hơn. Chúng ta chỉ ngừng cho nó thử lại mà không có ngân sách.” — [12:40]

Video không đề cập

Chi phí mỗi nhiệm vụ thành công và điều gì xảy ra khi nguồn truy xuất sai.

Nguồn

  • Video: https://www.youtube.com/watch?v=...
  • Benchmark liên kết: https://example.com/benchmark

Các lệnh gọi chính xác

Dành cho lập trình viên: cùng quy trình dưới dạng mã, theo thứ tự chạy.

Hiện lệnh gọi API thật
  1. Lấy bản ghi có timestamp

    Dùng YouTube Subtitling lấy phụ đề ngôn ngữ đích, giữ thời điểm bắt đầu và độ dài mỗi dòng.

    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;
    }

    Kết quả mẫu

    {
      "title": "How we rebuilt onboarding",
      "contents": [
        { "text": "Welcome back to the channel.", "start": 0.32, "duration": 4.1 }
      ]
    }
  2. Chia thành đoạn dễ đọc

    Chia theo chủ đề, bỏ từ đệm và giữ timestamp.

    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");
    }

    Kết quả mẫu

    [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. Lấy nguồn được nhắc

    Dùng Web Fetch đọc các trang được nêu trong video và thêm liên kết, dữ kiện.

    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 };
        }),
      );
    }

    Kết quả mẫu

    [
      {
        "url": "https://example.com/reference",
        "content": "# Reference\n\nExtracted page text…"
      }
    ]
  4. Lập dàn ý rồi viết bản nháp

    Xin dàn ý từ Model API trước, rồi viết bài theo dàn ý với trích ngắn và timestamp.

    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,
      };
    }

    Kết quả mẫu

    {
      "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. Để trong LiveDoc chờ biên tập

    Lưu bản nháp và trích dẫn vào LiveDoc, chuyển cho biên tập viên sửa và duyệt.

    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;
    }

    Kết quả mẫu

    { "short_id": "PvyKouzJirXjFdst4uKRK3" }

Bao gồm

  • Bản ghi YouTube có timestamp
  • Trang được video nhắc đến ở dạng Markdown
  • Dàn ý và bản nháp từ Model API
  • LiveDoc với bản nháp để biên tập

Không làm gì

  • Không chép toàn bộ bản ghi; chỉ trích ngắn và viết lại
  • Video cần có phụ đề
  • Kiểm tra quyền và giới hạn trích dẫn trước khi xuất bản
  • Model làm dàn ý và bản nháp; quyết định cuối thuộc biên tập viên
  • Không tự xuất bản hay dịch

Câu hỏi

Video có cần phụ đề không?

Có. Quy trình bắt đầu từ phụ đề; nếu thiếu, nó dừng thay vì đoán điều đã nói.

Có biến podcast thành bài được không?

Quy trình này dành cho YouTube. Với podcast, tạo bản ghi trước rồi dùng cùng quy tắc viết.

Có thể viết bằng ngôn ngữ khác không?

Có. Nêu ngôn ngữ đích; trích dẫn giữ nguyên bản gốc kèm bản dịch khi cần.

Ai viết bài?

Agent AI nơi bạn dán prompt viết bản nháp; Felo cung cấp bản ghi, trang và không gian biên tập.

Có được đăng lại toàn bộ bản ghi không?

Không. Quy trình tạo bài mới với trích ngắn và không sao chép toàn bộ bản ghi.

Một lần chạy tốn bao nhiêu?

Bản ghi và trích xuất trang tính theo mức dùng; giá hiện tại ở trang giá và prompt hỏi duyệt trước khi chi.

Quy trình liên quan

Tùy biến

Cùng công thức, điều chỉnh theo cách bạn thực sự triển khai.

Chỉ trích dẫn có timestamp

Không viết bài; giao danh sách trích dẫn kiểm tra được để tái sử dụng.

Bản newsletter trước

Rút bài thành bản ngắn, trò chuyện hơn cho newsletter.

Xử lý kênh theo lô

Lặp các bước cho từng video và lưu LiveDoc riêng.

Các trang tham chiếu đằng sau công thức và nơi đi tiếp.