marketing-pipeline-share-ai-content

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Ultimate AI Content Pipeline

终极AI内容流水线

Skill by ara.so — Marketing Skills collection.
This skill enables AI coding agents to work with the Ultimate AI Content Pipeline - a comprehensive system that automates content creation from research to video generation using Claude 3, OpenAI, and Remotion.
ara.so提供的技能 — 营销技能合集。
本技能支持AI编码Agent使用终极AI内容流水线——一套借助Claude 3、OpenAI和Remotion实现从调研到视频生成全流程自动化的内容创作系统。

What This Project Does

项目功能介绍

The Ultimate AI Content Pipeline is an end-to-end content automation system that:
  • Auto-crawls trending news from TechCrunch, a16z, Twitter, LinkedIn
  • Generates content in multiple formats (Toplist, POV, Case Study, How-to)
  • Supports bilingual content (English & Vietnamese)
  • Renders videos automatically using Remotion for Reels, TikTok, Shorts
  • Integrates OpenAI, Anthropic Claude, and RapidAPI
Built with TypeScript and Next.js, it transforms a single keyword into complete content ready for publishing.
终极AI内容流水线是一套端到端的内容自动化系统,具备以下功能:
  • 自动爬取TechCrunch、a16z、Twitter、LinkedIn上的热门资讯
  • 生成多格式内容(榜单、观点文、案例研究、教程)
  • 支持双语内容(英文与越南语)
  • 借助Remotion自动渲染视频,适配Reels、TikTok、Shorts等平台
  • 集成OpenAI、Anthropic Claude和RapidAPI
基于TypeScript和Next.js构建,只需一个关键词即可生成可直接发布的完整内容。

Installation

安装步骤

Prerequisites

前置要求

bash
undefined
bash
undefined

Node.js 18+ required

需要Node.js 18及以上版本

node --version
node --version

Clone the repository

克隆仓库

git clone https://github.com/pennydinh/marketing-pineline-share.git cd marketing-pineline-share
git clone https://github.com/pennydinh/marketing-pineline-share.git cd marketing-pineline-share

Install dependencies

安装依赖

npm install
npm install

or

yarn install
yarn install

or

pnpm install
undefined
pnpm install
undefined

Environment Configuration

环境配置

Create a
.env.local
file in the root directory:
bash
undefined
在根目录创建
.env.local
文件:
bash
undefined

AI Provider Keys

AI服务提供商密钥

OPENAI_API_KEY=your_openai_key_here ANTHROPIC_API_KEY=your_claude_key_here
OPENAI_API_KEY=your_openai_key_here ANTHROPIC_API_KEY=your_claude_key_here

RapidAPI for news crawling

用于资讯爬取的RapidAPI密钥

RAPIDAPI_KEY=your_rapidapi_key_here
RAPIDAPI_KEY=your_rapidapi_key_here

Remotion configuration

Remotion配置

REMOTION_LICENSE_KEY=your_remotion_license_here
REMOTION_LICENSE_KEY=your_remotion_license_here

Database (if applicable)

数据库(如有需要)

DATABASE_URL=your_database_connection_string
DATABASE_URL=your_database_connection_string

Next.js configuration

Next.js配置

NEXT_PUBLIC_API_URL=http://localhost:3000
undefined
NEXT_PUBLIC_API_URL=http://localhost:3000
undefined

Running the Development Server

启动开发服务器

bash
npm run dev
bash
npm run dev

or

yarn dev
yarn dev

or

pnpm dev

Access the application at `http://localhost:3000`
pnpm dev

访问应用地址:`http://localhost:3000`

Core Components and API

核心组件与API

1. Research & Content Crawling

1. 调研与内容爬取

typescript
// lib/research/crawler.ts
import { fetchNewsFromSources } from './sources';

interface ResearchResult {
  title: string;
  url: string;
  content: string;
  source: string;
  publishedAt: Date;
  insights: string[];
}

async function crawlTrendingTopics(
  keyword: string,
  timeframe: '24h' | '7d' = '24h'
): Promise<ResearchResult[]> {
  const sources = ['techcrunch', 'a16z', 'twitter', 'linkedin'];
  
  const results = await Promise.all(
    sources.map(source => 
      fetchNewsFromSources(source, keyword, timeframe)
    )
  );
  
  return results.flat();
}

// Usage
const research = await crawlTrendingTopics('AI marketing', '24h');
typescript
// lib/research/crawler.ts
import { fetchNewsFromSources } from './sources';

interface ResearchResult {
  title: string;
  url: string;
  content: string;
  source: string;
  publishedAt: Date;
  insights: string[];
}

async function crawlTrendingTopics(
  keyword: string,
  timeframe: '24h' | '7d' = '24h'
): Promise<ResearchResult[]> {
  const sources = ['techcrunch', 'a16z', 'twitter', 'linkedin'];
  
  const results = await Promise.all(
    sources.map(source => 
      fetchNewsFromSources(source, keyword, timeframe)
    )
  );
  
  return results.flat();
}

// 使用示例
const research = await crawlTrendingTopics('AI marketing', '24h');

2. AI Content Generation

2. AI内容生成

typescript
// lib/ai/content-generator.ts
import Anthropic from '@anthropic-ai/sdk';
import OpenAI from 'openai';

type ContentFormat = 'toplist' | 'pov' | 'case-study' | 'how-to';
type Language = 'en' | 'vi';
type Tone = 'expert' | 'friendly' | 'humorous';

interface ContentConfig {
  format: ContentFormat;
  language: Language;
  tone: Tone;
  targetAudience: string;
}

async function generateContent(
  research: ResearchResult[],
  config: ContentConfig
): Promise<string> {
  const anthropic = new Anthropic({
    apiKey: process.env.ANTHROPIC_API_KEY,
  });

  const prompt = buildPrompt(research, config);

  const message = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 4096,
    messages: [
      {
        role: 'user',
        content: prompt,
      },
    ],
  });

  return message.content[0].type === 'text' 
    ? message.content[0].text 
    : '';
}

function buildPrompt(
  research: ResearchResult[],
  config: ContentConfig
): string {
  const researchSummary = research
    .map(r => `- ${r.title}: ${r.insights.join(', ')}`)
    .join('\n');

  return `
You are a ${config.tone} content creator writing in ${config.language}.
Create a ${config.format} article for ${config.targetAudience}.

Research data from the last 24 hours:
${researchSummary}

Requirements:
- Use data-backed insights
- Include specific examples and numbers
- Make it engaging and actionable
- Format: ${config.format}
`;
}

// Usage
const content = await generateContent(research, {
  format: 'toplist',
  language: 'en',
  tone: 'expert',
  targetAudience: 'B2B marketers',
});
typescript
// lib/ai/content-generator.ts
import Anthropic from '@anthropic-ai/sdk';
import OpenAI from 'openai';

type ContentFormat = 'toplist' | 'pov' | 'case-study' | 'how-to';
type Language = 'en' | 'vi';
type Tone = 'expert' | 'friendly' | 'humorous';

interface ContentConfig {
  format: ContentFormat;
  language: Language;
  tone: Tone;
  targetAudience: string;
}

async function generateContent(
  research: ResearchResult[],
  config: ContentConfig
): Promise<string> {
  const anthropic = new Anthropic({
    apiKey: process.env.ANTHROPIC_API_KEY,
  });

  const prompt = buildPrompt(research, config);

  const message = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 4096,
    messages: [
      {
        role: 'user',
        content: prompt,
      },
    ],
  });

  return message.content[0].type === 'text' 
    ? message.content[0].text 
    : '';
}

function buildPrompt(
  research: ResearchResult[],
  config: ContentConfig
): string {
  const researchSummary = research
    .map(r => `- ${r.title}: ${r.insights.join(', ')}`)
    .join('\n');

  return `
You are a ${config.tone} content creator writing in ${config.language}.
Create a ${config.format} article for ${config.targetAudience}.

Research data from the last 24 hours:
${researchSummary}

Requirements:
- Use data-backed insights
- Include specific examples and numbers
- Make it engaging and actionable
- Format: ${config.format}
`;
}

// 使用示例
const content = await generateContent(research, {
  format: 'toplist',
  language: 'en',
  tone: 'expert',
  targetAudience: 'B2B marketers',
});

3. Bilingual Content Generation

3. 双语内容生成

typescript
// lib/ai/bilingual-generator.ts
async function generateBilingualContent(
  research: ResearchResult[],
  baseConfig: Omit<ContentConfig, 'language'>
): Promise<{ en: string; vi: string }> {
  const [englishContent, vietnameseContent] = await Promise.all([
    generateContent(research, { ...baseConfig, language: 'en' }),
    generateContent(research, { ...baseConfig, language: 'vi' }),
  ]);

  return {
    en: englishContent,
    vi: vietnameseContent,
  };
}

// Usage
const bilingualContent = await generateBilingualContent(research, {
  format: 'how-to',
  tone: 'friendly',
  targetAudience: 'content creators',
});
typescript
// lib/ai/bilingual-generator.ts
async function generateBilingualContent(
  research: ResearchResult[],
  baseConfig: Omit<ContentConfig, 'language'>
): Promise<{ en: string; vi: string }> {
  const [englishContent, vietnameseContent] = await Promise.all([
    generateContent(research, { ...baseConfig, language: 'en' }),
    generateContent(research, { ...baseConfig, language: 'vi' }),
  ]);

  return {
    en: englishContent,
    vi: vietnameseContent,
  };
}

// 使用示例
const bilingualContent = await generateBilingualContent(research, {
  format: 'how-to',
  tone: 'friendly',
  targetAudience: 'content creators',
});

4. Video Generation with Remotion

4. 基于Remotion的视频生成

typescript
// lib/video/renderer.ts
import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
import path from 'path';

interface VideoConfig {
  content: string;
  format: 'reels' | 'tiktok' | 'shorts'; // all use 9:16
  duration: number; // in frames (30fps)
}

async function generateVideo(config: VideoConfig): Promise<string> {
  const compositionId = 'ContentVideo';
  const bundleLocation = await bundle(
    path.join(process.cwd(), 'remotion', 'index.ts')
  );

  const composition = await selectComposition({
    serveUrl: bundleLocation,
    id: compositionId,
    inputProps: {
      content: config.content,
      platform: config.format,
    },
  });

  const outputPath = path.join(
    process.cwd(),
    'public',
    'videos',
    `${Date.now()}.mp4`
  );

  await renderMedia({
    composition,
    serveUrl: bundleLocation,
    codec: 'h264',
    outputLocation: outputPath,
    inputProps: {
      content: config.content,
      platform: config.format,
    },
  });

  return outputPath;
}

// Usage
const videoPath = await generateVideo({
  content: bilingualContent.en,
  format: 'reels',
  duration: 900, // 30 seconds at 30fps
});
typescript
// lib/video/renderer.ts
import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
import path from 'path';

interface VideoConfig {
  content: string;
  format: 'reels' | 'tiktok' | 'shorts'; // 均采用9:16比例
  duration: number; // 帧数(30fps)
}

async function generateVideo(config: VideoConfig): Promise<string> {
  const compositionId = 'ContentVideo';
  const bundleLocation = await bundle(
    path.join(process.cwd(), 'remotion', 'index.ts')
  );

  const composition = await selectComposition({
    serveUrl: bundleLocation,
    id: compositionId,
    inputProps: {
      content: config.content,
      platform: config.format,
    },
  });

  const outputPath = path.join(
    process.cwd(),
    'public',
    'videos',
    `${Date.now()}.mp4`
  );

  await renderMedia({
    composition,
    serveUrl: bundleLocation,
    codec: 'h264',
    outputLocation: outputPath,
    inputProps: {
      content: config.content,
      platform: config.format,
    },
  });

  return outputPath;
}

// 使用示例
const videoPath = await generateVideo({
  content: bilingualContent.en,
  format: 'reels',
  duration: 900, // 30fps下为30秒
});

5. Remotion Video Component

5. Remotion视频组件

typescript
// remotion/ContentVideo.tsx
import { AbsoluteFill, useCurrentFrame, useVideoConfig } from 'remotion';
import React from 'react';

interface ContentVideoProps {
  content: string;
  platform: 'reels' | 'tiktok' | 'shorts';
}

export const ContentVideo: React.FC<ContentVideoProps> = ({
  content,
  platform,
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // Parse content into scenes
  const scenes = parseContentIntoScenes(content);
  const currentScene = Math.floor(frame / (fps * 3)); // 3 seconds per scene

  return (
    <AbsoluteFill
      style={{
        backgroundColor: '#000',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <div
        style={{
          fontSize: 48,
          color: '#fff',
          textAlign: 'center',
          padding: 40,
          maxWidth: '80%',
        }}
      >
        {scenes[currentScene]?.text || ''}
      </div>
    </AbsoluteFill>
  );
};

function parseContentIntoScenes(content: string) {
  // Split content into digestible scenes
  const sentences = content.match(/[^.!?]+[.!?]+/g) || [];
  return sentences.map((text, index) => ({
    id: index,
    text: text.trim(),
  }));
}
typescript
// remotion/ContentVideo.tsx
import { AbsoluteFill, useCurrentFrame, useVideoConfig } from 'remotion';
import React from 'react';

interface ContentVideoProps {
  content: string;
  platform: 'reels' | 'tiktok' | 'shorts';
}

export const ContentVideo: React.FC<ContentVideoProps> = ({
  content,
  platform,
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // 将内容解析为场景
  const scenes = parseContentIntoScenes(content);
  const currentScene = Math.floor(frame / (fps * 3)); // 每个场景3秒

  return (
    <AbsoluteFill
      style={{
        backgroundColor: '#000',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <div
        style={{
          fontSize: 48,
          color: '#fff',
          textAlign: 'center',
          padding: 40,
          maxWidth: '80%',
        }}
      >
        {scenes[currentScene]?.text || ''}
      </div>
    </AbsoluteFill>
  );
};

function parseContentIntoScenes(content: string) {
  // 将内容拆分为易读的场景
  const sentences = content.match(/[^.!?]+[.!?]+/g) || [];
  return sentences.map((text, index) => ({
    id: index,
    text: text.trim(),
  }));
}

6. Remotion Configuration

6. Remotion配置

typescript
// remotion/config.ts
import { Config } from '@remotion/cli/config';

Config.setVideoImageFormat('jpeg');
Config.setOverwriteOutput(true);
Config.setConcurrency(4);

// For license key
Config.setLicenseKey(process.env.REMOTION_LICENSE_KEY);
typescript
// remotion/config.ts
import { Config } from '@remotion/cli/config';

Config.setVideoImageFormat('jpeg');
Config.setOverwriteOutput(true);
Config.setConcurrency(4);

// 配置许可证密钥
Config.setLicenseKey(process.env.REMOTION_LICENSE_KEY);

Complete Workflow Pattern

完整工作流示例

typescript
// app/api/generate-content/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  try {
    const { keyword, format, language, generateVideo } = await req.json();

    // Step 1: Research
    const research = await crawlTrendingTopics(keyword, '24h');

    // Step 2: Generate Content
    let content: string;
    
    if (language === 'both') {
      const bilingual = await generateBilingualContent(research, {
        format,
        tone: 'expert',
        targetAudience: 'marketers',
      });
      content = bilingual.en;
    } else {
      content = await generateContent(research, {
        format,
        language,
        tone: 'expert',
        targetAudience: 'marketers',
      });
    }

    // Step 3: Generate Video (optional)
    let videoUrl = null;
    if (generateVideo) {
      const videoPath = await generateVideo({
        content,
        format: 'reels',
        duration: 900,
      });
      videoUrl = `/videos/${path.basename(videoPath)}`;
    }

    return NextResponse.json({
      success: true,
      content,
      videoUrl,
      research: research.length,
    });
  } catch (error) {
    console.error('Content generation error:', error);
    return NextResponse.json(
      { success: false, error: error.message },
      { status: 500 }
    );
  }
}
typescript
// app/api/generate-content/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  try {
    const { keyword, format, language, generateVideo } = await req.json();

    // 步骤1:调研
    const research = await crawlTrendingTopics(keyword, '24h');

    // 步骤2:生成内容
    let content: string;
    
    if (language === 'both') {
      const bilingual = await generateBilingualContent(research, {
        format,
        tone: 'expert',
        targetAudience: 'marketers',
      });
      content = bilingual.en;
    } else {
      content = await generateContent(research, {
        format,
        language,
        tone: 'expert',
        targetAudience: 'marketers',
      });
    }

    // 步骤3:生成视频(可选)
    let videoUrl = null;
    if (generateVideo) {
      const videoPath = await generateVideo({
        content,
        format: 'reels',
        duration: 900,
      });
      videoUrl = `/videos/${path.basename(videoPath)}`;
    }

    return NextResponse.json({
      success: true,
      content,
      videoUrl,
      research: research.length,
    });
  } catch (error) {
    console.error('内容生成错误:', error);
    return NextResponse.json(
      { success: false, error: error.message },
      { status: 500 }
    );
  }
}

Frontend Integration

前端集成示例

typescript
// app/page.tsx
'use client';

import { useState } from 'react';

export default function Home() {
  const [keyword, setKeyword] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);

  async function handleGenerate() {
    setLoading(true);
    
    const response = await fetch('/api/generate-content', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        keyword,
        format: 'toplist',
        language: 'both',
        generateVideo: true,
      }),
    });

    const data = await response.json();
    setResult(data);
    setLoading(false);
  }

  return (
    <div className="container mx-auto p-8">
      <h1 className="text-4xl font-bold mb-8">
        AI Content Pipeline
      </h1>
      
      <div className="space-y-4">
        <input
          type="text"
          value={keyword}
          onChange={(e) => setKeyword(e.target.value)}
          placeholder="Enter keyword..."
          className="w-full p-4 border rounded"
        />
        
        <button
          onClick={handleGenerate}
          disabled={loading}
          className="px-6 py-3 bg-blue-600 text-white rounded"
        >
          {loading ? 'Generating...' : 'Generate Content'}
        </button>

        {result?.content && (
          <div className="mt-8 p-6 bg-gray-50 rounded">
            <h2 className="text-2xl font-bold mb-4">Generated Content</h2>
            <div className="prose max-w-none">
              {result.content}
            </div>
            {result.videoUrl && (
              <video
                src={result.videoUrl}
                controls
                className="mt-4 w-full max-w-md"
              />
            )}
          </div>
        )}
      </div>
    </div>
  );
}
typescript
// app/page.tsx
'use client';

import { useState } from 'react';

export default function Home() {
  const [keyword, setKeyword] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);

  async function handleGenerate() {
    setLoading(true);
    
    const response = await fetch('/api/generate-content', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        keyword,
        format: 'toplist',
        language: 'both',
        generateVideo: true,
      }),
    });

    const data = await response.json();
    setResult(data);
    setLoading(false);
  }

  return (
    <div className="container mx-auto p-8">
      <h1 className="text-4xl font-bold mb-8">
        AI内容流水线
      </h1>
      
      <div className="space-y-4">
        <input
          type="text"
          value={keyword}
          onChange={(e) => setKeyword(e.target.value)}
          placeholder="输入关键词..."
          className="w-full p-4 border rounded"
        />
        
        <button
          onClick={handleGenerate}
          disabled={loading}
          className="px-6 py-3 bg-blue-600 text-white rounded"
        >
          {loading ? '生成中...' : '生成内容'}
        </button>

        {result?.content && (
          <div className="mt-8 p-6 bg-gray-50 rounded">
            <h2 className="text-2xl font-bold mb-4">生成的内容</h2>
            <div className="prose max-w-none">
              {result.content}
            </div>
            {result.videoUrl && (
              <video
                src={result.videoUrl}
                controls
                className="mt-4 w-full max-w-md"
              />
            )}
          </div>
        )}
      </div>
    </div>
  );
}

Configuration Patterns

配置扩展示例

Custom AI Providers

自定义AI服务提供商

typescript
// lib/ai/providers.ts
type AIProvider = 'claude' | 'openai';

interface ProviderConfig {
  provider: AIProvider;
  model: string;
  temperature?: number;
  maxTokens?: number;
}

async function generateWithProvider(
  prompt: string,
  config: ProviderConfig
): Promise<string> {
  switch (config.provider) {
    case 'claude':
      return generateWithClaude(prompt, config);
    case 'openai':
      return generateWithOpenAI(prompt, config);
    default:
      throw new Error(`Unknown provider: ${config.provider}`);
  }
}

async function generateWithOpenAI(
  prompt: string,
  config: ProviderConfig
): Promise<string> {
  const openai = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY,
  });

  const completion = await openai.chat.completions.create({
    model: config.model || 'gpt-4-turbo-preview',
    messages: [{ role: 'user', content: prompt }],
    temperature: config.temperature || 0.7,
    max_tokens: config.maxTokens || 4096,
  });

  return completion.choices[0]?.message?.content || '';
}
typescript
// lib/ai/providers.ts
type AIProvider = 'claude' | 'openai';

interface ProviderConfig {
  provider: AIProvider;
  model: string;
  temperature?: number;
  maxTokens?: number;
}

async function generateWithProvider(
  prompt: string,
  config: ProviderConfig
): Promise<string> {
  switch (config.provider) {
    case 'claude':
      return generateWithClaude(prompt, config);
    case 'openai':
      return generateWithOpenAI(prompt, config);
    default:
      throw new Error(`未知服务提供商: ${config.provider}`);
  }
}

async function generateWithOpenAI(
  prompt: string,
  config: ProviderConfig
): Promise<string> {
  const openai = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY,
  });

  const completion = await openai.chat.completions.create({
    model: config.model || 'gpt-4-turbo-preview',
    messages: [{ role: 'user', content: prompt }],
    temperature: config.temperature || 0.7,
    max_tokens: config.maxTokens || 4096,
  });

  return completion.choices[0]?.message?.content || '';
}

Content Scheduling

内容调度

typescript
// lib/scheduler/schedule.ts
interface ScheduledContent {
  content: string;
  videoUrl?: string;
  platforms: ('facebook' | 'instagram' | 'tiktok')[];
  scheduledTime: Date;
}

async function scheduleContent(
  scheduled: ScheduledContent
): Promise<void> {
  // Store in database with scheduled time
  await db.scheduledPosts.create({
    data: {
      content: scheduled.content,
      videoUrl: scheduled.videoUrl,
      platforms: scheduled.platforms,
      scheduledFor: scheduled.scheduledTime,
      status: 'pending',
    },
  });
}
typescript
// lib/scheduler/schedule.ts
interface ScheduledContent {
  content: string;
  videoUrl?: string;
  platforms: ('facebook' | 'instagram' | 'tiktok')[];
  scheduledTime: Date;
}

async function scheduleContent(
  scheduled: ScheduledContent
): Promise<void> {
  // 将内容存储到数据库并设置发布时间
  await db.scheduledPosts.create({
    data: {
      content: scheduled.content,
      videoUrl: scheduled.videoUrl,
      platforms: scheduled.platforms,
      scheduledFor: scheduled.scheduledTime,
      status: 'pending',
    },
  });
}

Troubleshooting

故障排查

API Rate Limits

API速率限制

typescript
// lib/utils/rate-limiter.ts
class RateLimiter {
  private queue: Array<() => Promise<any>> = [];
  private processing = false;
  private delay: number;

  constructor(requestsPerMinute: number) {
    this.delay = 60000 / requestsPerMinute;
  }

  async add<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });
      this.process();
    });
  }

  private async process() {
    if (this.processing || this.queue.length === 0) return;
    
    this.processing = true;
    const fn = this.queue.shift();
    
    if (fn) {
      await fn();
      await new Promise(resolve => setTimeout(resolve, this.delay));
    }
    
    this.processing = false;
    this.process();
  }
}

// Usage
const limiter = new RateLimiter(10); // 10 requests per minute
const result = await limiter.add(() => generateContent(research, config));
typescript
// lib/utils/rate-limiter.ts
class RateLimiter {
  private queue: Array<() => Promise<any>> = [];
  private processing = false;
  private delay: number;

  constructor(requestsPerMinute: number) {
    this.delay = 60000 / requestsPerMinute;
  }

  async add<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });
      this.process();
    });
  }

  private async process() {
    if (this.processing || this.queue.length === 0) return;
    
    this.processing = true;
    const fn = this.queue.shift();
    
    if (fn) {
      await fn();
      await new Promise(resolve => setTimeout(resolve, this.delay));
    }
    
    this.processing = false;
    this.process();
  }
}

// 使用示例
const limiter = new RateLimiter(10); // 每分钟10次请求
const result = await limiter.add(() => generateContent(research, config));

Video Rendering Timeout

视频渲染超时

typescript
// Increase timeout for long videos
await renderMedia({
  composition,
  serveUrl: bundleLocation,
  codec: 'h264',
  outputLocation: outputPath,
  timeoutInMilliseconds: 300000, // 5 minutes
  inputProps: config,
});
typescript
// 为长视频增加超时时间
await renderMedia({
  composition,
  serveUrl: bundleLocation,
  codec: 'h264',
  outputLocation: outputPath,
  timeoutInMilliseconds: 300000, // 5分钟
  inputProps: config,
});

Memory Issues with Large Content

大内容内存问题

typescript
// Process content in chunks
async function generateLongFormContent(
  research: ResearchResult[],
  config: ContentConfig,
  sections: number = 5
): Promise<string> {
  const chunks = chunkArray(research, Math.ceil(research.length / sections));
  
  const sectionContents = await Promise.all(
    chunks.map(chunk => generateContent(chunk, config))
  );
  
  return sectionContents.join('\n\n---\n\n');
}

function chunkArray<T>(array: T[], size: number): T[][] {
  return Array.from(
    { length: Math.ceil(array.length / size) },
    (_, i) => array.slice(i * size, i * size + size)
  );
}
typescript
// 分块处理内容
async function generateLongFormContent(
  research: ResearchResult[],
  config: ContentConfig,
  sections: number = 5
): Promise<string> {
  const chunks = chunkArray(research, Math.ceil(research.length / sections));
  
  const sectionContents = await Promise.all(
    chunks.map(chunk => generateContent(chunk, config))
  );
  
  return sectionContents.join('\n\n---\n\n');
}

function chunkArray<T>(array: T[], size: number): T[][] {
  return Array.from(
    { length: Math.ceil(array.length / size) },
    (_, i) => array.slice(i * size, i * size + size)
  );
}

Environment Variable Validation

环境变量验证

typescript
// lib/config/validate.ts
function validateEnv() {
  const required = [
    'OPENAI_API_KEY',
    'ANTHROPIC_API_KEY',
    'RAPIDAPI_KEY',
  ];

  const missing = required.filter(key => !process.env[key]);

  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables: ${missing.join(', ')}`
    );
  }
}

// Call on startup
validateEnv();
typescript
// lib/config/validate.ts
function validateEnv() {
  const required = [
    'OPENAI_API_KEY',
    'ANTHROPIC_API_KEY',
    'RAPIDAPI_KEY',
  ];

  const missing = required.filter(key => !process.env[key]);

  if (missing.length > 0) {
    throw new Error(
      `缺少必要的环境变量: ${missing.join(', ')}`
    );
  }
}

// 在启动时调用
validateEnv();

Common Use Cases

常见使用场景

Daily Content Automation

日常内容自动化

typescript
// scripts/daily-automation.ts
async function runDailyContentPipeline() {
  const topics = ['AI marketing', 'content automation', 'social media trends'];
  
  for (const topic of topics) {
    const research = await crawlTrendingTopics(topic, '24h');
    
    const content = await generateBilingualContent(research, {
      format: 'toplist',
      tone: 'friendly',
      targetAudience: 'marketers',
    });
    
    const videoPath = await generateVideo({
      content: content.en,
      format: 'reels',
      duration: 900,
    });
    
    await scheduleContent({
      content: content.en,
      videoUrl: `/videos/${path.basename(videoPath)}`,
      platforms: ['instagram', 'tiktok'],
      scheduledTime: new Date(Date.now() + 86400000), // Tomorrow
    });
  }
}
This skill provides comprehensive guidance for AI coding agents to effectively use the Ultimate AI Content Pipeline for automated content creation and distribution.
typescript
// scripts/daily-automation.ts
async function runDailyContentPipeline() {
  const topics = ['AI marketing', 'content automation', 'social media trends'];
  
  for (const topic of topics) {
    const research = await crawlTrendingTopics(topic, '24h');
    
    const content = await generateBilingualContent(research, {
      format: 'toplist',
      tone: 'friendly',
      targetAudience: 'marketers',
    });
    
    const videoPath = await generateVideo({
      content: content.en,
      format: 'reels',
      duration: 900,
    });
    
    await scheduleContent({
      content: content.en,
      videoUrl: `/videos/${path.basename(videoPath)}`,
      platforms: ['instagram', 'tiktok'],
      scheduledTime: new Date(Date.now() + 86400000), // 明天发布
    });
  }
}
本技能为AI编码Agent提供了全面指导,帮助其有效使用终极AI内容流水线实现自动化内容创作与分发。