marketing-pipeline-share-ai-content
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUltimate 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
undefinedbash
undefinedNode.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
undefinedpnpm install
undefinedEnvironment Configuration
环境配置
Create a file in the root directory:
.env.localbash
undefined在根目录创建文件:
.env.localbash
undefinedAI 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
undefinedNEXT_PUBLIC_API_URL=http://localhost:3000
undefinedRunning the Development Server
启动开发服务器
bash
npm run devbash
npm run devor
或
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内容流水线实现自动化内容创作与分发。