エージェントファクトリー完全ガイド2025 - モジュール型AI自動化パイプライン構築
モジュール型AIエージェントファクトリーの設計と実装方法を徹底解説。再利用可能なコンポーネントを組み合わせて、複雑なAIワークフローを効率的に構築する手法を実践的に紹介します。
JavaScriptでOpenAI APIとFlikiを統合し、テキストから動画まで一気通貫でコンテンツを自動生成するシステムの構築方法を徹底解説。ブログ記事、SNS投稿、動画コンテンツまで全自動化を実現します。
AI の進化により、テキストコンテンツの生成から動画制作まで、 すべてのコンテンツ制作プロセスを自動化できる時代が到来しました。 本記事では、JavaScript、OpenAI、Fliki を統合した包括的なコンテンツ生成システムの構築方法を解説します。
チャートを読み込み中...
コンポーネント | 役割 | 使用技術 | メリット |
---|---|---|---|
Content Generator | AIによるテキスト生成 | OpenAI GPT-4 | 高品質な文章生成 |
Video Creator | 動画コンテンツ生成 | Fliki AI | 2500+音声、80+言語対応 |
Pipeline Manager | ワークフロー管理 | Node.js/JavaScript | 柔軟な処理フロー |
Format Optimizer | フォーマット最適化 | Custom Processors | マルチチャネル対応 |
Distribution System | 自動配信 | API Integrations | 一括配信管理 |
Analytics Engine | 効果測定 | Analytics APIs | データドリブン改善 |
# プロジェクトの初期化
npm init -y
# 必要なパッケージのインストール
npm install openai axios dotenv
npm install @ffmpeg-installer/ffmpeg fluent-ffmpeg
npm install node-schedule winston
npm install express multer
# 開発用パッケージ
npm install -D @types/node typescript nodemon
npm install -D eslint prettier jest
# プロジェクトの初期化
yarn init -y
# 必要なパッケージのインストール
yarn add openai axios dotenv
yarn add @ffmpeg-installer/ffmpeg fluent-ffmpeg
yarn add node-schedule winston
yarn add express multer
# 開発用パッケージ
yarn add -D @types/node typescript nodemon
yarn add -D eslint prettier jest
# プロジェクトの初期化
pnpm init
# 必要なパッケージのインストール
pnpm add openai axios dotenv
pnpm add @ffmpeg-installer/ffmpeg fluent-ffmpeg
pnpm add node-schedule winston
pnpm add express multer
# 開発用パッケージ
pnpm add -D @types/node typescript nodemon
pnpm add -D eslint prettier jest
// config/environment.js
import dotenv from 'dotenv';
dotenv.config();
export const config = {
openai: {
apiKey: process.env.OPENAI_API_KEY,
model: process.env.OPENAI_MODEL || 'gpt-4',
maxTokens: parseInt(process.env.MAX_TOKENS || '2000'),
temperature: parseFloat(process.env.TEMPERATURE || '0.7'),
},
fliki: {
apiKey: process.env.FLIKI_API_KEY,
apiUrl: process.env.FLIKI_API_URL || 'https://api.fliki.ai/v1',
defaultVoice: process.env.DEFAULT_VOICE || 'Sara',
defaultLanguage: process.env.DEFAULT_LANGUAGE || 'ja',
},
content: {
outputDir: process.env.OUTPUT_DIR || './generated-content',
cacheEnabled: process.env.CACHE_ENABLED === 'true',
cacheTTL: parseInt(process.env.CACHE_TTL || '3600'),
},
limits: {
maxConcurrentGenerations: parseInt(process.env.MAX_CONCURRENT || '5'),
rateLimitPerMinute: parseInt(process.env.RATE_LIMIT || '10'),
}
};
高品質なコンテンツ生成の鍵は、適切なプロンプト設計にあります。 システムプロンプトとユーザープロンプトを組み合わせて、 一貫性のある高品質なコンテンツを生成しましょう。
// src/generators/content-generator.js
import OpenAI from 'openai';
import { config } from '../config/environment.js';
import { PromptTemplate } from './prompt-template.js';
export class ContentGenerator {
constructor() {
this.openai = new OpenAI({
apiKey: config.openai.apiKey,
});
this.promptTemplate = new PromptTemplate();
}
async generateContent(options) {
const {
topic,
contentType = 'blog',
tone = 'professional',
language = 'ja',
keywords = [],
targetLength = 1000,
} = options;
try {
// プロンプトの構築
const prompt = this.promptTemplate.build({
contentType,
topic,
tone,
language,
keywords,
targetLength,
});
// OpenAI APIコール
const response = await this.openai.chat.completions.create({
model: config.openai.model,
messages: [
{
role: 'system',
content: this.getSystemPrompt(contentType, language),
},
{
role: 'user',
content: prompt,
},
],
max_tokens: config.openai.maxTokens,
temperature: config.openai.temperature,
});
const generatedContent = response.choices[0].message.content;
// 後処理
return this.postProcess(generatedContent, options);
} catch (error) {
console.error('Content generation error:', error);
throw new Error(`Failed to generate content: ${error.message}`);
}
}
getSystemPrompt(contentType, language) {
const prompts = {
blog: {
ja: `あなたは優秀なブログライターです。SEOに最適化された、読者にとって価値のある記事を作成してください。
以下の要素を含めてください:
- 魅力的なタイトル
- 導入部で読者の興味を引く
- 構造化された見出し(H2、H3)
- 具体例やデータの引用
- 実践的なアドバイス
- まとめと次のステップ`,
en: `You are an excellent blog writer. Create SEO-optimized, valuable content for readers.`
},
social: {
ja: `あなたはソーシャルメディアの専門家です。エンゲージメントを最大化する投稿を作成してください。`,
en: `You are a social media expert. Create posts that maximize engagement.`
},
video_script: {
ja: `あなたは動画スクリプトライターです。視聴者を引き付ける魅力的なスクリプトを作成してください。`,
en: `You are a video script writer. Create engaging scripts that captivate viewers.`
},
};
return prompts[contentType]?.[language] || prompts.blog.ja;
}
async postProcess(content, options) {
// フォーマット別の後処理
switch (options.contentType) {
case 'blog':
return this.formatBlogPost(content, options);
case 'social':
return this.formatSocialPost(content, options);
case 'video_script':
return this.formatVideoScript(content, options);
default:
return content;
}
}
formatBlogPost(content, options) {
// メタデータの追加
const metadata = {
title: this.extractTitle(content),
description: this.generateDescription(content),
keywords: options.keywords,
readingTime: this.calculateReadingTime(content),
wordCount: content.split(/\s+/).length,
};
return {
content,
metadata,
format: 'markdown',
};
}
extractTitle(content) {
const titleMatch = content.match(/^#\s+(.+)$/m);
return titleMatch ? titleMatch[1] : 'Untitled';
}
generateDescription(content, maxLength = 160) {
// 最初の段落を抽出して説明文として使用
const firstParagraph = content
.split('\n\n')
.find(p => p.trim() && !p.startsWith('#'));
if (!firstParagraph) return '';
return firstParagraph.length > maxLength
? firstParagraph.substring(0, maxLength - 3) + '...'
: firstParagraph;
}
calculateReadingTime(content) {
const wordsPerMinute = 200; // 日本語の平均読書速度
const wordCount = content.length; // 日本語は文字数でカウント
return Math.ceil(wordCount / wordsPerMinute);
}
}
// src/generators/prompt-template.js
export class PromptTemplate {
constructor() {
this.templates = {
blog: this.blogTemplate,
social: this.socialTemplate,
video_script: this.videoScriptTemplate,
};
}
build(options) {
const template = this.templates[options.contentType];
if (!template) {
throw new Error(`Unknown content type: ${options.contentType}`);
}
return template.call(this, options);
}
blogTemplate(options) {
return `
【タスク】${options.topic}に関するブログ記事を作成してください。
【要件】
- トーン: ${options.tone}
- 文字数: ${options.targetLength}文字程度
- 言語: ${options.language === 'ja' ? '日本語' : '英語'}
- キーワード: ${options.keywords.join(', ')}
【構成】
1. 魅力的なタイトル(SEO最適化)
2. 導入部(読者の課題や関心事に触れる)
3. 本論(3-5つの主要ポイント)
- 各ポイントに具体例やデータを含める
- 実践的なアドバイスを提供
4. まとめ(要点の整理と次のアクション)
【追加要件】
- 見出しは階層構造(H2、H3)で整理
- 専門用語は初出時に説明
- 読者が実践できる具体的なステップを含める
`;
}
socialTemplate(options) {
const platformLimits = {
twitter: 280,
instagram: 2200,
linkedin: 3000,
facebook: 63206,
};
const limit = platformLimits[options.platform] || 500;
return `
【タスク】${options.topic}についての${options.platform}投稿を作成してください。
【要件】
- 文字数制限: ${limit}文字
- トーン: ${options.tone}
- ハッシュタグ: ${options.keywords.map(k => `#${k}`).join(' ')}を含める
【投稿の要素】
- アテンションを引く冒頭
- 価値提供(情報、インサイト、エンターテイメント)
- 行動喚起(CTA)
- 適切な絵文字の使用
【プラットフォーム特有の考慮事項】
${this.getPlatformGuidelines(options.platform)}
`;
}
videoScriptTemplate(options) {
return `
【タスク】${options.topic}に関する${options.duration || 3}分間の動画スクリプトを作成してください。
【動画の構成】
1. フック(0-5秒): 視聴者の注意を引く
2. イントロ(5-15秒): 動画の内容を簡潔に説明
3. メインコンテンツ(${options.duration * 60 - 30}秒):
- ポイントを明確に分ける
- ビジュアルの指示を含める
- トランジションを明記
4. まとめとCTA(15秒): 要点整理と次のアクション
【スクリプトフォーマット】
- ナレーション部分は【ナレーション】タグで囲む
- ビジュアル指示は【ビジュアル】タグで囲む
- BGMや効果音の指示は【音声】タグで囲む
【トーン】
${options.tone}で、視聴者とのつながりを意識した話し方
`;
}
getPlatformGuidelines(platform) {
const guidelines = {
twitter: '- 簡潔で印象的な表現\n- リツイートされやすい内容\n- スレッド形式も検討',
instagram: '- ビジュアルを意識した説明\n- ストーリー性のある内容\n- 適切な改行で読みやすく',
linkedin: '- プロフェッショナルな内容\n- 業界インサイトや学び\n- 個人的な経験を交える',
facebook: '- 会話的なトーン\n- コミュニティとの対話を促す\n- 感情に訴える要素',
};
return guidelines[platform] || '';
}
}
// src/integrations/fliki-client.js
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs/promises';
import path from 'path';
import { config } from '../config/environment.js';
export class FlikiClient {
constructor() {
this.apiUrl = config.fliki.apiUrl;
this.apiKey = config.fliki.apiKey;
this.defaultVoice = config.fliki.defaultVoice;
this.defaultLanguage = config.fliki.defaultLanguage;
}
async createVideo(options) {
const {
script,
title,
voice = this.defaultVoice,
language = this.defaultLanguage,
backgroundMusic = true,
subtitles = true,
aspectRatio = '16:9',
quality = 'high',
} = options;
try {
// プロジェクトの作成
const project = await this.createProject({
title,
aspectRatio,
language,
});
// シーンの追加
const scenes = this.parseScriptToScenes(script);
for (const scene of scenes) {
await this.addScene(project.id, {
...scene,
voice,
language,
});
}
// 動画の生成
const video = await this.generateVideo(project.id, {
quality,
backgroundMusic,
subtitles,
});
// 生成状態の監視
const finalVideo = await this.waitForCompletion(video.id);
return {
videoUrl: finalVideo.url,
projectId: project.id,
duration: finalVideo.duration,
metadata: {
title,
language,
voice,
createdAt: new Date().toISOString(),
},
};
} catch (error) {
console.error('Fliki video creation error:', error);
throw new Error(`Failed to create video: ${error.message}`);
}
}
async createProject(projectData) {
const response = await axios.post(
`${this.apiUrl}/projects`,
projectData,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
}
);
return response.data;
}
parseScriptToScenes(script) {
// スクリプトをシーンに分割
const scenes = [];
const sceneRegex = /【シーン】(.+?)【\/シーン】/gs;
const matches = [...script.matchAll(sceneRegex)];
if (matches.length === 0) {
// シーンタグがない場合は段落で分割
const paragraphs = script.split('\n\n').filter(p => p.trim());
return paragraphs.map((text, index) => ({
order: index + 1,
text: this.extractNarration(text),
visuals: this.extractVisuals(text),
duration: this.estimateDuration(text),
}));
}
matches.forEach((match, index) => {
const sceneContent = match[1];
scenes.push({
order: index + 1,
text: this.extractNarration(sceneContent),
visuals: this.extractVisuals(sceneContent),
duration: this.estimateDuration(sceneContent),
});
});
return scenes;
}
extractNarration(text) {
const narrationMatch = text.match(/【ナレーション】(.+?)【\/ナレーション】/s);
return narrationMatch ? narrationMatch[1].trim() : text.trim();
}
extractVisuals(text) {
const visualMatch = text.match(/【ビジュアル】(.+?)【\/ビジュアル】/s);
return visualMatch ? visualMatch[1].trim() : null;
}
estimateDuration(text) {
// 日本語の読み上げ速度(1分あたり300文字)を基に推定
const charCount = this.extractNarration(text).length;
return Math.ceil((charCount / 300) * 60);
}
async addScene(projectId, sceneData) {
const response = await axios.post(
`${this.apiUrl}/projects/${projectId}/scenes`,
sceneData,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
}
);
return response.data;
}
async generateVideo(projectId, options) {
const response = await axios.post(
`${this.apiUrl}/projects/${projectId}/generate`,
options,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
}
);
return response.data;
}
async waitForCompletion(videoId, maxWaitTime = 600000) {
const startTime = Date.now();
const pollInterval = 5000; // 5秒ごとにポーリング
while (Date.now() - startTime < maxWaitTime) {
const status = await this.checkVideoStatus(videoId);
if (status.state === 'completed') {
return status;
} else if (status.state === 'failed') {
throw new Error(`Video generation failed: ${status.error}`);
}
// 待機
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Video generation timeout');
}
async checkVideoStatus(videoId) {
const response = await axios.get(
`${this.apiUrl}/videos/${videoId}/status`,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
},
}
);
return response.data;
}
}
動画生成はコストがかかるため、以下の最適化戦略を実装しています:
// src/optimizers/video-optimizer.js
export class VideoOptimizer {
constructor(cacheManager) {
this.cache = cacheManager;
this.costCalculator = new CostCalculator();
}
async optimizeVideoGeneration(content, options) {
// キャッシュチェック
const cacheKey = this.generateCacheKey(content, options);
const cached = await this.cache.get(cacheKey);
if (cached) {
console.log('Using cached video:', cacheKey);
return cached;
}
// コスト見積もり
const estimatedCost = this.costCalculator.estimate({
duration: options.duration,
quality: options.quality,
features: options.features,
});
// 品質の動的調整
if (estimatedCost > options.maxCost) {
options = this.adjustQualityForCost(options, estimatedCost);
}
// シーン最適化
const optimizedScenes = this.optimizeScenes(content.scenes);
return {
...content,
scenes: optimizedScenes,
options: options,
estimatedCost: estimatedCost,
};
}
optimizeScenes(scenes) {
return scenes.map(scene => ({
...scene,
// 長すぎるシーンを分割
...(scene.duration > 30 ? this.splitScene(scene) : {}),
// ビジュアルの最適化
visuals: this.optimizeVisuals(scene.visuals),
}));
}
adjustQualityForCost(options, currentCost) {
const qualityLevels = ['ultra', 'high', 'medium', 'low'];
let currentIndex = qualityLevels.indexOf(options.quality);
while (currentCost > options.maxCost && currentIndex < qualityLevels.length - 1) {
currentIndex++;
options.quality = qualityLevels[currentIndex];
currentCost = this.costCalculator.estimate(options);
}
return options;
}
}
チャートを読み込み中...
// src/pipeline/content-pipeline.js
import { ContentGenerator } from '../generators/content-generator.js';
import { FlikiClient } from '../integrations/fliki-client.js';
import { ContentOptimizer } from '../optimizers/content-optimizer.js';
import { DistributionManager } from '../distribution/distribution-manager.js';
import { AnalyticsTracker } from '../analytics/analytics-tracker.js';
import EventEmitter from 'events';
export class ContentPipeline extends EventEmitter {
constructor(options = {}) {
super();
this.generator = new ContentGenerator();
this.flikiClient = new FlikiClient();
this.optimizer = new ContentOptimizer();
this.distributor = new DistributionManager();
this.analytics = new AnalyticsTracker();
this.options = {
parallel: true,
maxConcurrent: 5,
retryAttempts: 3,
...options,
};
this.queue = [];
this.processing = new Set();
}
async execute(request) {
const jobId = this.generateJobId();
this.emit('job:start', { jobId, request });
try {
// バリデーション
this.validateRequest(request);
// コンテンツ生成フェーズ
const generatedContent = await this.generatePhase(request);
// 最適化フェーズ
const optimizedContent = await this.optimizePhase(generatedContent, request);
// 配信フェーズ
const distributionResult = await this.distributePhase(optimizedContent, request);
// 分析フェーズ
await this.analyticsPhase(distributionResult, request);
this.emit('job:complete', {
jobId,
result: distributionResult,
metrics: await this.getJobMetrics(jobId),
});
return {
success: true,
jobId,
content: optimizedContent,
distribution: distributionResult,
};
} catch (error) {
this.emit('job:error', { jobId, error });
throw error;
}
}
async generatePhase(request) {
const { contentTypes, topic, options } = request;
const results = {};
// 並列生成
const generateTasks = contentTypes.map(async (type) => {
const content = await this.generator.generateContent({
topic,
contentType: type,
...options[type],
});
results[type] = content;
// 動画コンテンツの場合はFliki処理
if (type === 'video' || request.generateVideo) {
const videoScript = type === 'video'
? content.content
: await this.convertToVideoScript(content);
const video = await this.flikiClient.createVideo({
script: videoScript,
title: content.metadata.title,
...options.video,
});
results.video = video;
}
});
await Promise.all(generateTasks);
return results;
}
async optimizePhase(content, request) {
const optimized = {};
for (const [type, data] of Object.entries(content)) {
optimized[type] = await this.optimizer.optimize(data, {
type,
target: request.targets?.[type],
constraints: request.constraints,
});
}
return optimized;
}
async distributePhase(content, request) {
if (!request.distribute) {
return { distributed: false };
}
const distributionTasks = request.channels.map(async (channel) => {
const channelContent = content[channel.contentType] || content.blog;
return this.distributor.publish({
channel: channel.name,
content: channelContent,
scheduledAt: channel.scheduledAt,
options: channel.options,
});
});
const results = await Promise.all(distributionTasks);
return {
distributed: true,
channels: results,
timestamp: new Date().toISOString(),
};
}
async analyticsPhase(distributionResult, request) {
if (!distributionResult.distributed) {
return;
}
// 配信結果の追跡設定
for (const channel of distributionResult.channels) {
await this.analytics.trackContent({
contentId: channel.contentId,
channel: channel.name,
metrics: request.trackingMetrics || ['views', 'engagement', 'conversions'],
});
}
}
async convertToVideoScript(content) {
// ブログコンテンツを動画スクリプトに変換
const prompt = `
以下のコンテンツを3分間の動画スクリプトに変換してください:
${content.content}
要件:
- 視覚的な要素の追加
- ナレーションの最適化
- シーン分割
`;
const scriptContent = await this.generator.generateContent({
topic: prompt,
contentType: 'video_script',
});
return scriptContent.content;
}
validateRequest(request) {
const required = ['contentTypes', 'topic'];
for (const field of required) {
if (!request[field]) {
throw new Error(`Missing required field: ${field}`);
}
}
if (!Array.isArray(request.contentTypes) || request.contentTypes.length === 0) {
throw new Error('contentTypes must be a non-empty array');
}
}
generateJobId() {
return `job_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
async getJobMetrics(jobId) {
return {
processingTime: Date.now() - this.getJobStartTime(jobId),
tokensUsed: await this.calculateTokenUsage(jobId),
estimatedCost: await this.calculateCost(jobId),
};
}
}
チャネル | 最適化項目 | 自動化機能 | 分析項目 |
---|---|---|---|
ブログ | SEO、読みやすさ | WordPress投稿 | PV、滞在時間 |
YouTube | サムネイル、タグ | アップロード、公開設定 | 視聴時間、CTR |
文字数、ハッシュタグ | スレッド投稿 | インプレッション、RT | |
画像生成、キャプション | ストーリー、リール | リーチ、保存数 | |
プロフェッショナル調整 | 記事投稿 | ビュー、シェア |
// src/distribution/distribution-manager.js
import { WordPressClient } from './clients/wordpress-client.js';
import { YouTubeClient } from './clients/youtube-client.js';
import { SocialMediaClient } from './clients/social-media-client.js';
import { ScheduleManager } from './schedule-manager.js';
export class DistributionManager {
constructor() {
this.clients = {
wordpress: new WordPressClient(),
youtube: new YouTubeClient(),
twitter: new SocialMediaClient('twitter'),
instagram: new SocialMediaClient('instagram'),
linkedin: new SocialMediaClient('linkedin'),
};
this.scheduler = new ScheduleManager();
}
async publish(publishRequest) {
const { channel, content, scheduledAt, options } = publishRequest;
// スケジュール投稿の場合
if (scheduledAt && new Date(scheduledAt) > new Date()) {
return this.scheduler.schedule({
task: () => this.publishNow(channel, content, options),
scheduledAt,
metadata: { channel, contentId: content.id },
});
}
// 即時投稿
return this.publishNow(channel, content, options);
}
async publishNow(channel, content, options) {
const client = this.clients[channel];
if (!client) {
throw new Error(`Unsupported channel: ${channel}`);
}
// チャネル別の前処理
const processedContent = await this.preprocessContent(channel, content);
// 投稿実行
const result = await client.publish(processedContent, options);
// 投稿後の処理
await this.postPublish(channel, result);
return {
channel,
contentId: result.id,
url: result.url,
publishedAt: new Date().toISOString(),
status: 'published',
};
}
async preprocessContent(channel, content) {
const processors = {
wordpress: this.preprocessWordPress,
youtube: this.preprocessYouTube,
twitter: this.preprocessTwitter,
instagram: this.preprocessInstagram,
linkedin: this.preprocessLinkedIn,
};
const processor = processors[channel];
return processor ? processor.call(this, content) : content;
}
preprocessWordPress(content) {
return {
title: content.metadata.title,
content: content.content,
excerpt: content.metadata.description,
categories: this.mapCategories(content.metadata.keywords),
tags: content.metadata.keywords,
featured_media: content.metadata.featuredImage,
meta: {
seo_title: content.metadata.seoTitle || content.metadata.title,
seo_description: content.metadata.description,
keywords: content.metadata.keywords.join(', '),
},
};
}
preprocessYouTube(content) {
return {
title: this.optimizeYouTubeTitle(content.metadata.title),
description: this.generateYouTubeDescription(content),
tags: this.optimizeYouTubeTags(content.metadata.keywords),
thumbnail: content.metadata.thumbnail,
videoFile: content.videoUrl,
privacy: 'public',
category: this.mapYouTubeCategory(content.metadata.category),
};
}
optimizeYouTubeTitle(title) {
// YouTubeのタイトル最適化(100文字制限)
const maxLength = 100;
if (title.length <= maxLength) {
return title;
}
// 重要なキーワードを前に配置
const optimized = title.substring(0, maxLength - 3) + '...';
return optimized;
}
generateYouTubeDescription(content) {
const template = `
${content.metadata.description}
📌 チャプター
${this.generateChapters(content)}
🔗 関連リンク
${this.generateRelatedLinks(content)}
📱 SNSでフォロー
Twitter: @channel
Instagram: @channel
#${content.metadata.keywords.join(' #')}
`;
return template.trim();
}
}
// src/optimization/cost-manager.js
export class CostManager {
constructor() {
this.pricing = {
openai: {
'gpt-4': { input: 0.03, output: 0.06 }, // per 1K tokens
'gpt-3.5-turbo': { input: 0.001, output: 0.002 },
},
fliki: {
minute: 0.5, // per minute of video
voice: {
standard: 0,
premium: 0.2,
},
},
};
this.monthlyBudget = {
total: 1000,
allocated: {},
spent: {},
};
}
async optimizeRequest(request, currentUsage) {
const estimatedCost = this.estimateCost(request);
const remainingBudget = this.getRemainingBudget();
if (estimatedCost > remainingBudget) {
return this.applyFallbackStrategy(request, remainingBudget);
}
// コスト効率の良いモデル選択
if (request.contentType === 'social' && estimatedCost > 1) {
request.model = 'gpt-3.5-turbo'; // 簡単なコンテンツには安価なモデル
}
return request;
}
estimateCost(request) {
let cost = 0;
// テキスト生成コスト
if (request.model && request.estimatedTokens) {
const pricing = this.pricing.openai[request.model];
cost += (request.estimatedTokens.input / 1000) * pricing.input;
cost += (request.estimatedTokens.output / 1000) * pricing.output;
}
// 動画生成コスト
if (request.generateVideo) {
const videoDuration = request.videoDuration || 3; // minutes
cost += videoDuration * this.pricing.fliki.minute;
if (request.voiceType === 'premium') {
cost += videoDuration * this.pricing.fliki.voice.premium;
}
}
return cost;
}
applyFallbackStrategy(request, budget) {
// 予算内に収まるように調整
const strategies = [
() => { request.model = 'gpt-3.5-turbo'; },
() => { request.maxTokens = Math.floor(request.maxTokens * 0.7); },
() => { request.generateVideo = false; },
() => { request.videoQuality = 'medium'; },
];
let adjustedRequest = { ...request };
let estimatedCost = this.estimateCost(adjustedRequest);
for (const strategy of strategies) {
if (estimatedCost <= budget) break;
strategy.call(null, adjustedRequest);
estimatedCost = this.estimateCost(adjustedRequest);
}
return adjustedRequest;
}
}
AI コンテンツ生成システムの導入により、商品ページの作成時間が 95%削減されました。 さらに、動画コンテンツの追加により、コンバージョン率が 45%向上し、 返品率も 20%減少しました。ROI は導入後 3 ヶ月で達成できました。
// examples/ecommerce-content-automation.js
async function generateProductContent(product) {
const pipeline = new ContentPipeline({
cacheEnabled: true,
costOptimization: true,
});
const request = {
contentTypes: ['blog', 'social', 'video'],
topic: `${product.name} - ${product.category}`,
options: {
blog: {
tone: 'informative',
targetLength: 1500,
keywords: [...product.tags, product.brand, product.category],
includeSpecs: true,
includeBenefits: true,
},
social: {
platforms: ['instagram', 'twitter', 'facebook'],
tone: 'exciting',
includePrice: true,
promotionCode: product.promotionCode,
},
video: {
duration: 60, // 1分の商品紹介動画
style: 'product_showcase',
includeTestimonials: true,
voice: 'Yuki', // 日本語の声優
},
},
distribute: true,
channels: [
{
name: 'wordpress',
contentType: 'blog',
scheduledAt: null, // 即時公開
},
{
name: 'youtube',
contentType: 'video',
scheduledAt: getOptimalPublishTime('youtube'),
},
{
name: 'instagram',
contentType: 'social',
scheduledAt: getOptimalPublishTime('instagram'),
},
],
};
const result = await pipeline.execute(request);
// 生成されたコンテンツのURLを商品データベースに保存
await updateProductContent(product.id, {
blogUrl: result.distribution.channels[0].url,
videoUrl: result.distribution.channels[1].url,
socialLinks: result.distribution.channels.slice(2).map(c => c.url),
});
return result;
}
トレンド分析に基づくトピック自動選定
複数フォーマットで同時生成
AI+人間によるハイブリッド確認
最適なタイミングで自動配信
リアルタイムでパフォーマンス追跡