ALwrity Version 0.5.0 (Fastapi + React )

This commit is contained in:
ajaysi
2025-08-06 12:48:02 +05:30
parent f28a919caa
commit 32f97fa6b3
476 changed files with 115544 additions and 28747 deletions

View File

@@ -0,0 +1,690 @@
import { apiClient, aiApiClient } from '../api/client';
// Types
export interface ContentStrategyCreate {
name: string;
description: string;
industry: string;
target_audience: string;
content_pillars: string[];
user_id?: number;
}
export interface ContentStrategyUpdate {
name?: string;
description?: string;
industry?: string;
target_audience?: string;
content_pillars?: string[];
}
export interface CalendarEventCreate {
title: string;
description: string;
date: string;
platform: string;
content_type: string;
status: 'draft' | 'scheduled' | 'published';
strategy_id?: string;
user_id?: number;
}
export interface CalendarEventUpdate {
title?: string;
description?: string;
date?: string;
platform?: string;
content_type?: string;
status?: 'draft' | 'scheduled' | 'published';
strategy_id?: string;
}
export interface GapAnalysisCreate {
website_url: string;
competitors: string[];
keywords: string[];
user_id?: number;
}
export interface GapAnalysisUpdate {
website_url?: string;
competitors?: string[];
keywords?: string[];
gaps?: string[];
recommendations?: any[];
}
export interface AIAnalyticsCreate {
analysis_type: string;
data: any;
insights: any[];
user_id?: number;
}
export interface AIAnalyticsUpdate {
analysis_type?: string;
data?: any;
insights?: any[];
}
// New Calendar Generation Interfaces
export interface CalendarGenerationRequest {
user_id: number;
strategy_id?: number;
calendar_type: string;
industry?: string;
business_size: string;
force_refresh?: boolean;
}
export interface CalendarGenerationResponse {
user_id: number;
strategy_id?: number;
calendar_type: string;
industry: string;
business_size: string;
generated_at: string;
content_pillars: string[];
platform_strategies: any;
content_mix: Record<string, number>;
daily_schedule: any[];
weekly_themes: any[];
content_recommendations: any[];
optimal_timing: any;
performance_predictions: any;
trending_topics: any[];
repurposing_opportunities: any[];
ai_insights: any[];
competitor_analysis: any;
gap_analysis_insights: any;
strategy_insights: any;
onboarding_insights: any;
processing_time: number;
ai_confidence: number;
}
export interface ContentOptimizationRequest {
user_id: number;
event_id?: number;
title: string;
description: string;
content_type: string;
target_platform: string;
original_content?: any;
}
export interface ContentOptimizationResponse {
user_id: number;
event_id?: number;
original_content: any;
optimized_content: any;
platform_adaptations: string[];
visual_recommendations: string[];
hashtag_suggestions: string[];
keyword_optimization: any;
tone_adjustments: any;
length_optimization: any;
performance_prediction: any;
optimization_score: number;
created_at: string;
}
export interface PerformancePredictionRequest {
user_id: number;
strategy_id?: number;
content_type: string;
platform: string;
content_data: any;
}
export interface PerformancePredictionResponse {
user_id: number;
strategy_id?: number;
content_type: string;
platform: string;
predicted_engagement_rate: number;
predicted_reach: number;
predicted_conversions: number;
predicted_roi: number;
confidence_score: number;
recommendations: string[];
created_at: string;
}
export interface ContentRepurposingRequest {
user_id: number;
strategy_id?: number;
original_content: any;
target_platforms: string[];
}
export interface ContentRepurposingResponse {
user_id: number;
strategy_id?: number;
original_content: any;
platform_adaptations: any[];
transformations: any[];
implementation_tips: string[];
gap_addresses: string[];
created_at: string;
}
export interface TrendingTopicsRequest {
user_id: number;
industry: string;
limit?: number;
}
export interface TrendingTopicsResponse {
user_id: number;
industry: string;
trending_topics: any[];
gap_relevance_scores: Record<string, number>;
audience_alignment_scores: Record<string, number>;
created_at: string;
}
// Content Planning API Service
class ContentPlanningAPI {
private baseURL = '/api/content-planning';
// Content Strategy APIs
async createStrategy(strategy: ContentStrategyCreate) {
const response = await apiClient.post(`${this.baseURL}/strategies/`, strategy);
return response.data;
}
async getStrategies(userId?: number) {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/strategies/`, { params });
return response.data;
}
async getStrategy(id: string) {
const response = await apiClient.get(`${this.baseURL}/strategies/${id}`);
return response.data;
}
async updateStrategy(id: string, updates: ContentStrategyUpdate) {
const response = await apiClient.put(`${this.baseURL}/strategies/${id}`, updates);
return response.data;
}
async deleteStrategy(id: string) {
const response = await apiClient.delete(`${this.baseURL}/strategies/${id}`);
return response.data;
}
// Calendar Event APIs
async createEvent(event: CalendarEventCreate) {
const response = await apiClient.post(`${this.baseURL}/calendar-events/`, event);
return response.data;
}
async getEvents(userId?: number, filters?: any) {
const params = { ...filters };
if (userId) params.user_id = userId;
const response = await apiClient.get(`${this.baseURL}/calendar-events/`, { params });
return response.data;
}
async getEvent(id: string) {
const response = await apiClient.get(`${this.baseURL}/calendar-events/${id}`);
return response.data;
}
async updateEvent(id: string, updates: CalendarEventUpdate) {
const response = await apiClient.put(`${this.baseURL}/calendar-events/${id}`, updates);
return response.data;
}
async deleteEvent(id: string) {
const response = await apiClient.delete(`${this.baseURL}/calendar-events/${id}`);
return response.data;
}
// Gap Analysis APIs
async createGapAnalysis(analysis: GapAnalysisCreate) {
const response = await apiClient.post(`${this.baseURL}/gap-analysis/`, analysis);
return response.data;
}
async getGapAnalyses(userId?: number) {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/gap-analysis/`, { params });
return response.data;
}
async getGapAnalysis(id: string) {
const response = await apiClient.get(`${this.baseURL}/gap-analysis/${id}`);
return response.data;
}
async updateGapAnalysis(id: string, updates: GapAnalysisUpdate) {
const response = await apiClient.put(`${this.baseURL}/gap-analysis/${id}`, updates);
return response.data;
}
async deleteGapAnalysis(id: string) {
const response = await apiClient.delete(`${this.baseURL}/gap-analysis/${id}`);
return response.data;
}
// AI-Powered Gap Analysis - Using AI client for longer timeout
async analyzeContentGaps(params: {
website_url: string;
competitors: string[];
keywords: string[];
user_id?: number;
}) {
const response = await aiApiClient.post(`${this.baseURL}/gap-analysis/analyze`, params);
return response.data;
}
// AI Analytics APIs - Using AI client for longer timeout
async createAIAnalytics(analytics: AIAnalyticsCreate) {
const response = await aiApiClient.post(`${this.baseURL}/ai-analytics/`, analytics);
return response.data;
}
async getAIAnalytics(userId?: number) {
const params = userId ? { user_id: userId } : {};
const response = await aiApiClient.get(`${this.baseURL}/ai-analytics/`, { params });
return response.data;
}
async getAIAnalyticsById(id: string) {
const response = await aiApiClient.get(`${this.baseURL}/ai-analytics/${id}`);
return response.data;
}
async updateAIAnalytics(id: string, updates: AIAnalyticsUpdate) {
const response = await aiApiClient.put(`${this.baseURL}/ai-analytics/${id}`, updates);
return response.data;
}
async deleteAIAnalytics(id: string) {
const response = await aiApiClient.delete(`${this.baseURL}/ai-analytics/${id}`);
return response.data;
}
// AI Analytics with Server-Sent Events
async streamAIAnalytics(
onProgress: (data: any) => void,
onComplete: (data: any) => void,
onError: (error: any) => void,
userId?: number
) {
try {
const params: Record<string, string> = {};
if (userId) {
params.user_id = userId.toString();
}
const queryString = new URLSearchParams(params).toString();
const url = `${this.baseURL}/ai-analytics/stream?${queryString}`;
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
switch (data.type) {
case 'connected':
onProgress({ message: data.message, progress: 0 });
break;
case 'progress':
onProgress({
message: data.message,
progress: data.progress,
step: data.step
});
break;
case 'complete':
onComplete(data);
eventSource.close();
break;
case 'error':
onError(new Error(data.message));
eventSource.close();
break;
}
} catch (parseError) {
onError(new Error('Failed to parse server message'));
}
};
eventSource.onerror = (error) => {
onError(new Error('EventSource failed'));
eventSource.close();
};
// Return cleanup function
return () => {
eventSource.close();
};
} catch (error: any) {
onError(error);
}
}
// Health Check APIs
async checkHealth() {
const response = await apiClient.get(`${this.baseURL}/health`);
return response.data;
}
async checkBackendHealth() {
const response = await apiClient.get(`${this.baseURL}/health/backend`);
return response.data;
}
async checkAIHealth() {
const response = await apiClient.get(`${this.baseURL}/health/ai`);
return response.data;
}
async checkDatabaseHealth() {
const response = await apiClient.get(`${this.baseURL}/database/health`);
return response.data;
}
// Error handling wrapper with AI-specific error messages
private async handleRequest<T>(request: () => Promise<T>, isAI: boolean = false): Promise<T> {
try {
return await request();
} catch (error: any) {
console.error('API Error:', error);
if (error.code === 'ECONNABORTED' || error.message?.includes('timeout')) {
if (isAI) {
throw new Error('AI analysis is taking longer than expected. This is normal for complex AI operations. Please wait a moment and try again.');
} else {
throw new Error('Request timed out. Please check your connection and try again.');
}
} else if (error.response) {
// Server responded with error status
const message = error.response.data?.detail || error.response.data?.message || 'API request failed';
throw new Error(message);
} else if (error.request) {
// Request was made but no response received
if (isAI) {
throw new Error('AI service is not responding. The AI analysis may be in progress. Please wait and try again.');
} else {
throw new Error('No response from server. Please check your connection.');
}
} else {
// Something else happened
throw new Error('An unexpected error occurred.');
}
}
}
// Wrapped methods with error handling
async createStrategySafe(strategy: ContentStrategyCreate) {
return this.handleRequest(() => this.createStrategy(strategy));
}
async getStrategiesSafe(userId?: number) {
return this.handleRequest(() => this.getStrategies(userId));
}
async createEventSafe(event: CalendarEventCreate) {
return this.handleRequest(() => this.createEvent(event));
}
async getEventsSafe(userId?: number, filters?: any) {
return this.handleRequest(() => this.getEvents(userId, filters));
}
async createGapAnalysisSafe(analysis: GapAnalysisCreate) {
return this.handleRequest(() => this.createGapAnalysis(analysis));
}
async getGapAnalysesSafe(userId?: number) {
return this.handleRequest(() => this.getGapAnalyses(userId));
}
async analyzeContentGapsSafe(params: {
website_url: string;
competitors: string[];
keywords: string[];
user_id?: number;
}) {
return this.handleRequest(() => this.analyzeContentGaps(params), true);
}
async getAIAnalyticsSafe(userId?: number) {
return this.handleRequest(() => this.getAIAnalytics(userId), true);
}
// AI Analytics with force refresh option
async getAIAnalyticsWithRefresh(userId?: number, forceRefresh = false): Promise<any> {
try {
const params: any = { user_id: userId || 1 };
if (forceRefresh) {
params.force_refresh = true;
}
const response = await apiClient.get(`${this.baseURL}/ai-analytics/`, { params });
return response.data;
} catch (error) {
console.error('Error getting AI analytics with refresh:', error);
return { insights: [], recommendations: [], total_insights: 0, total_recommendations: 0 };
}
}
async getGapAnalysesWithRefresh(userId?: number, forceRefresh = false): Promise<any> {
try {
const params: any = { user_id: userId || 1 };
if (forceRefresh) {
params.force_refresh = true;
}
const response = await apiClient.get(`${this.baseURL}/gap-analysis/`, { params });
return response.data;
} catch (error) {
console.error('Error getting gap analyses with refresh:', error);
return { gap_analyses: [], total_gaps: 0 };
}
}
// New Calendar Generation APIs
async generateCalendar(request: CalendarGenerationRequest): Promise<CalendarGenerationResponse> {
const response = await apiClient.post(`${this.baseURL}/generate-calendar`, request);
return response.data;
}
async optimizeContent(request: ContentOptimizationRequest): Promise<ContentOptimizationResponse> {
const response = await apiClient.post(`${this.baseURL}/optimize-content`, request);
return response.data;
}
async predictPerformance(request: PerformancePredictionRequest): Promise<PerformancePredictionResponse> {
const response = await apiClient.post(`${this.baseURL}/performance-predictions`, request);
return response.data;
}
async repurposeContent(request: ContentRepurposingRequest): Promise<ContentRepurposingResponse> {
const response = await apiClient.post(`${this.baseURL}/repurpose-content`, request);
return response.data;
}
async getTrendingTopics(request: TrendingTopicsRequest): Promise<TrendingTopicsResponse> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/trending-topics`, request);
return response.data;
});
}
async getComprehensiveUserData(userId?: number): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/comprehensive-user-data`, {
params: { user_id: userId }
});
return response.data;
});
}
async generateComprehensiveCalendar(config: any): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/generate-comprehensive-calendar`, config);
return response.data;
});
}
async checkCalendarGenerationHealth(): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/calendar-generation/health`);
return response.data;
});
}
// Enhanced Strategy API Methods
async createEnhancedStrategy(strategy: any): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies/create`, strategy);
// Extract data from the response wrapper
return response.data.data || response.data;
});
}
async updateEnhancedStrategy(id: string, updates: any): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.put(`${this.baseURL}/enhanced-strategies/${id}`, updates);
return response.data.data || response.data;
});
}
async deleteEnhancedStrategy(id: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.delete(`${this.baseURL}/enhanced-strategies/${id}`);
return response.data.data || response.data;
});
}
async getEnhancedStrategies(userId?: number): Promise<any> {
return this.handleRequest(async () => {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data.data || response.data;
});
}
async getEnhancedStrategy(id: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${id}`);
return response.data.data || response.data;
});
}
async generateEnhancedAIRecommendations(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies/${strategyId}/ai-recommendations`);
return response.data.data || response.data;
}, true);
}
async regenerateAIAnalysis(strategyId: string, analysisType: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies/${strategyId}/ai-analysis/regenerate`, {
analysis_type: analysisType
});
return response.data;
}, true);
}
async getEnhancedAIAnalyses(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/ai-analyses`);
return response.data;
});
}
async getOnboardingData(userId?: number): Promise<any> {
return this.handleRequest(async () => {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/onboarding-data`, { params });
return response.data;
});
}
async getOnboardingIntegration(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/onboarding-integration`);
return response.data;
});
}
async getEnhancedStrategyAnalytics(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/analytics`);
return response.data;
});
}
async getEnhancedStrategyCompletion(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/completion`);
return response.data;
});
}
async getEnhancedStrategyTooltips(): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/tooltips`);
return response.data;
});
}
async getEnhancedStrategyDisclosureSteps(): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/disclosure-steps`);
return response.data;
});
}
// Enhanced Strategy Streaming Methods
async streamEnhancedStrategies(userId?: number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/strategies?user_id=${userId || 1}`;
return new EventSource(url);
}
async streamStrategicIntelligence(userId?: number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/strategic-intelligence?user_id=${userId || 1}`;
return new EventSource(url);
}
async streamKeywordResearch(userId?: number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/keyword-research?user_id=${userId || 1}`;
return new EventSource(url);
}
// Helper method to handle SSE data
handleSSEData(eventSource: EventSource, onData: (data: any) => void, onError?: (error: any) => void, onComplete?: () => void) {
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
onData(data);
// Close connection when we get a result or error
if (data.type === 'result' || data.type === 'error') {
eventSource.close();
onComplete?.();
}
} catch (error) {
console.error('Error parsing SSE data:', error);
onError?.(error);
}
};
eventSource.onerror = (error) => {
console.error('SSE Error:', error);
onError?.(error);
eventSource.close();
};
return eventSource;
}
}
// Export singleton instance
export const contentPlanningApi = new ContentPlanningAPI();

View File

@@ -0,0 +1,403 @@
import { contentPlanningApi } from './contentPlanningApi';
export interface ServiceStatus {
name: string;
status: 'loading' | 'success' | 'error' | 'idle';
progress: number;
message: string;
data?: any;
error?: string;
}
export interface DashboardData {
strategies: any[];
gapAnalyses: any[];
aiInsights: any[];
aiRecommendations: any[];
calendarEvents: any[];
healthStatus: {
backend: boolean;
database: boolean;
aiServices: boolean;
};
}
export class ContentPlanningOrchestrator {
private serviceStatuses: Map<string, ServiceStatus> = new Map();
private onProgressUpdate?: (statuses: ServiceStatus[]) => void;
private onDataUpdate?: (data: Partial<DashboardData>) => void;
constructor() {
this.initializeServiceStatuses();
}
private initializeServiceStatuses() {
const services = [
{ name: 'strategies', displayName: 'Content Strategies' },
{ name: 'gapAnalyses', displayName: 'Gap Analysis' },
{ name: 'aiAnalytics', displayName: 'AI Analytics' },
{ name: 'calendarEvents', displayName: 'Calendar Events' },
{ name: 'healthCheck', displayName: 'System Health' }
];
services.forEach(service => {
this.serviceStatuses.set(service.name, {
name: service.displayName,
status: 'idle',
progress: 0,
message: 'Ready to load'
});
});
}
public setProgressCallback(callback: (statuses: ServiceStatus[]) => void) {
this.onProgressUpdate = callback;
}
public setDataUpdateCallback(callback: (data: Partial<DashboardData>) => void) {
this.onDataUpdate = callback;
}
private updateServiceStatus(name: string, updates: Partial<ServiceStatus>) {
const current = this.serviceStatuses.get(name);
if (current) {
const updated = { ...current, ...updates };
this.serviceStatuses.set(name, updated);
this.notifyProgressUpdate();
}
}
private notifyProgressUpdate() {
if (this.onProgressUpdate) {
this.onProgressUpdate(Array.from(this.serviceStatuses.values()));
}
}
private notifyDataUpdate(data: Partial<DashboardData>) {
if (this.onDataUpdate) {
this.onDataUpdate(data);
}
}
public async loadDashboardData(): Promise<DashboardData> {
// Reset all service statuses
this.serviceStatuses.forEach((status, name) => {
this.updateServiceStatus(name, {
status: 'loading',
progress: 0,
message: 'Initializing...'
});
});
// Start parallel requests
const promises = [
this.loadStrategies(),
this.loadGapAnalyses(),
this.loadAIAnalytics(),
this.loadCalendarEvents(),
this.loadHealthStatus()
];
// Wait for all to complete but handle each independently
const results = await Promise.allSettled(promises);
// Compile final data
const dashboardData: DashboardData = {
strategies: [],
gapAnalyses: [],
aiInsights: [],
aiRecommendations: [],
calendarEvents: [],
healthStatus: {
backend: false,
database: false,
aiServices: false
}
};
results.forEach((result) => {
if (result.status === 'fulfilled') {
const data = result.value;
// Type-safe data assignment
if ('strategies' in data) dashboardData.strategies = data.strategies;
if ('gapAnalyses' in data) dashboardData.gapAnalyses = data.gapAnalyses;
if ('aiInsights' in data) dashboardData.aiInsights = data.aiInsights;
if ('aiRecommendations' in data) dashboardData.aiRecommendations = data.aiRecommendations;
if ('calendarEvents' in data) dashboardData.calendarEvents = data.calendarEvents;
if ('healthStatus' in data) dashboardData.healthStatus = data.healthStatus;
}
});
return dashboardData;
}
private async loadStrategies() {
try {
this.updateServiceStatus('strategies', {
status: 'loading',
progress: 10,
message: 'Loading content strategies...'
});
const strategies = await contentPlanningApi.getStrategiesSafe();
this.updateServiceStatus('strategies', {
status: 'loading',
progress: 50,
message: 'Processing strategy data...'
});
// Simulate processing time for better UX
await new Promise(resolve => setTimeout(resolve, 500));
this.updateServiceStatus('strategies', {
status: 'success',
progress: 100,
message: `Loaded ${strategies.length} content strategies`,
data: strategies
});
this.notifyDataUpdate({ strategies });
return { strategies };
} catch (error: any) {
this.updateServiceStatus('strategies', {
status: 'error',
progress: 0,
message: 'Failed to load strategies',
error: error.message
});
return { strategies: [] };
}
}
private async loadGapAnalyses() {
try {
this.updateServiceStatus('gapAnalyses', {
status: 'loading',
progress: 10,
message: 'Initializing gap analysis...'
});
const response = await contentPlanningApi.getGapAnalysesSafe();
this.updateServiceStatus('gapAnalyses', {
status: 'loading',
progress: 30,
message: 'Analyzing content gaps...'
});
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, 800));
this.updateServiceStatus('gapAnalyses', {
status: 'loading',
progress: 70,
message: 'Processing gap analysis results...'
});
await new Promise(resolve => setTimeout(resolve, 500));
this.updateServiceStatus('gapAnalyses', {
status: 'success',
progress: 100,
message: `Found ${response.gap_analyses?.length || 0} content gaps`,
data: response
});
this.notifyDataUpdate({ gapAnalyses: response.gap_analyses || [] });
return { gapAnalyses: response.gap_analyses || [] };
} catch (error: any) {
this.updateServiceStatus('gapAnalyses', {
status: 'error',
progress: 0,
message: 'Failed to load gap analysis',
error: error.message
});
return { gapAnalyses: [] };
}
}
private async loadAIAnalytics() {
try {
this.updateServiceStatus('aiAnalytics', {
status: 'loading',
progress: 10,
message: 'Initializing AI analysis...'
});
return new Promise<{ aiInsights: any[]; aiRecommendations: any[] }>((resolve, reject) => {
contentPlanningApi.streamAIAnalytics(
// Progress callback
(progressData) => {
this.updateServiceStatus('aiAnalytics', {
progress: progressData.progress,
message: progressData.message || 'AI analysis in progress...'
});
},
// Complete callback
(aiData) => {
this.updateServiceStatus('aiAnalytics', {
status: 'success',
progress: 100,
message: `Generated ${aiData.insights?.length || 0} insights and ${aiData.recommendations?.length || 0} recommendations`,
data: aiData
});
this.notifyDataUpdate({
aiInsights: aiData.insights || [],
aiRecommendations: aiData.recommendations || []
});
resolve({
aiInsights: aiData.insights || [],
aiRecommendations: aiData.recommendations || []
});
},
// Error callback
(error) => {
this.updateServiceStatus('aiAnalytics', {
status: 'error',
progress: 0,
message: 'AI analysis failed',
error: error.message
});
reject(error);
}
);
});
} catch (error: any) {
this.updateServiceStatus('aiAnalytics', {
status: 'error',
progress: 0,
message: 'AI analysis failed',
error: error.message
});
return { aiInsights: [], aiRecommendations: [] };
}
}
private async loadCalendarEvents() {
try {
this.updateServiceStatus('calendarEvents', {
status: 'loading',
progress: 10,
message: 'Loading calendar events...'
});
const calendarEvents = await contentPlanningApi.getEventsSafe();
this.updateServiceStatus('calendarEvents', {
status: 'loading',
progress: 50,
message: 'Processing calendar data...'
});
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, 300));
this.updateServiceStatus('calendarEvents', {
status: 'success',
progress: 100,
message: `Loaded ${calendarEvents.length} calendar events`,
data: calendarEvents
});
this.notifyDataUpdate({ calendarEvents });
return { calendarEvents };
} catch (error: any) {
this.updateServiceStatus('calendarEvents', {
status: 'error',
progress: 0,
message: 'Failed to load calendar events',
error: error.message
});
return { calendarEvents: [] };
}
}
private async loadHealthStatus() {
try {
this.updateServiceStatus('healthCheck', {
status: 'loading',
progress: 25,
message: 'Checking system health...'
});
const [backendHealth, aiHealth] = await Promise.allSettled([
contentPlanningApi.checkBackendHealth(),
contentPlanningApi.checkAIHealth()
]);
const healthStatus = {
backend: backendHealth.status === 'fulfilled' && backendHealth.value.status === 'healthy',
database: backendHealth.status === 'fulfilled' && backendHealth.value.services?.database_connection === true,
aiServices: aiHealth.status === 'fulfilled' && aiHealth.value.status === 'healthy'
};
this.updateServiceStatus('healthCheck', {
status: 'success',
progress: 100,
message: 'System health check complete',
data: healthStatus
});
this.notifyDataUpdate({ healthStatus });
return { healthStatus };
} catch (error: any) {
this.updateServiceStatus('healthCheck', {
status: 'error',
progress: 0,
message: 'Health check failed',
error: error.message
});
return {
healthStatus: {
backend: false,
database: false,
aiServices: false
}
};
}
}
public getServiceStatuses(): ServiceStatus[] {
return Array.from(this.serviceStatuses.values());
}
public refreshService(serviceName: string) {
const status = this.serviceStatuses.get(serviceName);
if (status) {
this.updateServiceStatus(serviceName, {
status: 'loading',
progress: 0,
message: 'Refreshing...'
});
// Re-run the specific service
switch (serviceName) {
case 'strategies':
this.loadStrategies();
break;
case 'gapAnalyses':
this.loadGapAnalyses();
break;
case 'aiAnalytics':
this.loadAIAnalytics();
break;
case 'calendarEvents':
this.loadCalendarEvents();
break;
case 'healthCheck':
this.loadHealthStatus();
break;
}
}
}
}
// Export singleton instance
export const contentPlanningOrchestrator = new ContentPlanningOrchestrator();