ALwrity version 0.5.5

This commit is contained in:
ajaysi
2025-08-15 08:28:34 +05:30
parent 2b8c66c4d0
commit 55a97b2fd4
77 changed files with 8717 additions and 7567 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import {
Box,
Paper,
@@ -59,6 +59,7 @@ import StrategicInputField from './ContentStrategyBuilder/StrategicInputField';
import EnhancedTooltip from './ContentStrategyBuilder/EnhancedTooltip';
import AIRecommendationsPanel from './AIRecommendationsPanel';
import DataSourceTransparency from './DataSourceTransparency';
import StrategyAutofillTransparencyModal from './StrategyAutofillTransparencyModal';
// Import extracted hooks
import { useCategoryReview } from './ContentStrategyBuilder/hooks/useCategoryReview';
@@ -97,6 +98,20 @@ const ContentStrategyBuilder: React.FC = () => {
disclosureSteps,
currentStrategy,
updateFormField,
// Transparency state
transparencyModalOpen,
generationProgress: storeGenerationProgress,
currentPhase,
educationalContent: storeEducationalContent,
transparencyMessages,
isGenerating,
setTransparencyModalOpen,
setGenerationProgress: setStoreGenerationProgress,
setCurrentPhase,
setEducationalContent: setStoreEducationalContent,
addTransparencyMessage,
clearTransparencyMessages,
setIsGenerating,
validateFormField,
validateAllFields,
completeStep,
@@ -127,8 +142,8 @@ const ContentStrategyBuilder: React.FC = () => {
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [refreshError, setRefreshError] = useState<string | null>(null);
const [showEducationalModal, setShowEducationalModal] = useState(false);
const [educationalContent, setEducationalContent] = useState<any>(null);
const [generationProgress, setGenerationProgress] = useState<number>(0);
const [localEducationalContent, setLocalEducationalContent] = useState<any>(null);
const [localGenerationProgress, setLocalGenerationProgress] = useState<number>(0);
const [showAIRecModal, setShowAIRecModal] = useState(false);
// Ref to track if we've already set the default category
@@ -171,8 +186,8 @@ const ContentStrategyBuilder: React.FC = () => {
setError,
setCurrentStrategy,
setSaving,
setGenerationProgress,
setEducationalContent,
setGenerationProgress: setStoreGenerationProgress,
setEducationalContent: setStoreEducationalContent,
setShowEducationalModal,
validateAllFields,
getCompletionStats,
@@ -211,6 +226,21 @@ const ContentStrategyBuilder: React.FC = () => {
console.trace('📍 Stack trace for activeCategory change');
}, [activeCategory]);
// Monitor modal state for debugging
useEffect(() => {
console.log('🎯 Modal state changed - transparencyModalOpen:', transparencyModalOpen);
}, [transparencyModalOpen]);
// Monitor store data changes for debugging
useEffect(() => {
console.log('🎯 Store data changed:', {
autoPopulatedFieldsCount: Object.keys(autoPopulatedFields || {}).length,
dataSourcesCount: Object.keys(dataSources || {}).length,
inputDataPointsCount: Object.keys(inputDataPoints || {}).length,
transparencyMessagesCount: transparencyMessages?.length || 0
});
}, [autoPopulatedFields, dataSources, inputDataPoints, transparencyMessages]);
// Add CSS keyframes for pulse animation
useEffect(() => {
const style = document.createElement('style');
@@ -287,116 +317,207 @@ const ContentStrategyBuilder: React.FC = () => {
onRefreshData={() => autoPopulateFromOnboarding()}
onRefreshAI={async () => {
try {
// 🚀 POLLING-BASED AI REFRESH (No SSE)
// We switched from SSE to polling for better reliability
// This approach uses direct HTTP calls with visual feedback
// Open transparency modal and initialize transparency state
console.log('🎯 Opening transparency modal...');
setTransparencyModalOpen(true);
setIsGenerating(true);
setStoreGenerationProgress(0);
setCurrentPhase('autofill_initialization');
clearTransparencyMessages();
addTransparencyMessage('Starting strategy inputs generation process...');
console.log('🎯 Modal state set, transparency initialized');
setAIGenerating(true);
setIsRefreshing(true);
setRefreshError(null);
setRefreshMessage('Initializing refresh…');
setRefreshMessage('Initializing AI refresh…');
setRefreshProgress(5);
const es = await contentPlanningApi.streamAutofillRefresh(1, true, true);
es.onmessage = (evt: MessageEvent) => {
try {
const data = JSON.parse(evt.data);
if (data.type === 'status' || data.type === 'progress') {
setRefreshMessage(data.message || 'Refreshing…');
if (typeof data.progress === 'number') setRefreshProgress(data.progress);
}
if (data.type === 'result') {
const payload = data.data || {};
const fields = payload.fields || {};
const sources = payload.sources || {};
const inputDataPoints = payload.input_data_points || {};
const meta = payload.meta || {};
console.log('🎯 AI Refresh Result - Payload:', payload);
console.log('🎯 AI Refresh Result - Fields:', fields);
console.log('🎯 AI Refresh Result - Meta:', meta);
const fieldValues: Record<string, any> = {};
Object.keys(fields).forEach((fieldId) => {
const fieldData = fields[fieldId];
if (fieldData && typeof fieldData === 'object' && 'value' in fieldData) {
fieldValues[fieldId] = fieldData.value;
console.log(`✅ Processed field ${fieldId}:`, fieldData.value);
} else {
console.log(`❌ Skipped field ${fieldId}:`, fieldData);
}
});
console.log('🎯 Final fieldValues:', fieldValues);
useEnhancedStrategyStore.setState((state) => {
const newState = {
autoPopulatedFields: { ...state.autoPopulatedFields, ...fieldValues },
dataSources: { ...state.dataSources, ...sources },
inputDataPoints,
formData: { ...state.formData, ...fieldValues }
};
console.log('🎯 Updated store state:', newState);
return newState;
});
// Enhanced success/error messaging based on retry attempts and success rate
const attempts = meta.attempts || 1;
const successRate = meta.success_rate || 0;
const aiOverridesCount = meta.ai_overrides_count || 0;
if (!meta.ai_used || aiOverridesCount === 0) {
const msg = meta.error || 'AI did not produce new values. Please try again or complete onboarding data.';
setError(msg);
setRefreshError(msg);
setRefreshMessage(`No new AI values available. (${attempts} attempt${attempts > 1 ? 's' : ''})`);
} else {
// Show success message with retry info if applicable
if (attempts > 1) {
setRefreshMessage(`AI refresh completed successfully! Generated ${aiOverridesCount} fields in ${attempts} attempts (${successRate.toFixed(1)}% success rate).`);
} else {
setRefreshMessage(`AI refresh completed! Generated ${aiOverridesCount} fields (${successRate.toFixed(1)}% success rate).`);
}
// Show warning if success rate is low but we got some data
if (successRate < 70 && aiOverridesCount > 0) {
setRefreshError(`Warning: Only ${successRate.toFixed(1)}% of fields were filled. Some fields may need manual input.`);
}
}
es.close();
setAIGenerating(false);
setIsRefreshing(false);
// Clear success message after a delay
if (aiOverridesCount > 0) {
setTimeout(() => {
setRefreshMessage(null);
setRefreshProgress(0);
}, 5000);
}
}
if (data.type === 'error') {
const msg = data.message || 'AI refresh failed.';
setRefreshError(msg);
es.close();
setAIGenerating(false);
setIsRefreshing(false);
setRefreshMessage('Refresh failed.');
}
} catch (err: any) {
console.error('SSE parse error:', err);
// Start transparency message polling for visual feedback
const transparencyMessages = [
{ type: 'autofill_initialization', message: 'Starting strategy inputs generation process...', progress: 5 },
{ type: 'autofill_data_collection', message: 'Collecting and analyzing data sources...', progress: 15 },
{ type: 'autofill_data_quality', message: 'Assessing data quality and completeness...', progress: 25 },
{ type: 'autofill_context_analysis', message: 'Analyzing business context and strategic framework...', progress: 35 },
{ type: 'autofill_strategy_generation', message: 'Generating strategic insights and recommendations...', progress: 45 },
{ type: 'autofill_field_generation', message: 'Generating individual strategy input fields...', progress: 55 },
{ type: 'autofill_quality_validation', message: 'Validating generated strategy inputs...', progress: 65 },
{ type: 'autofill_alignment_check', message: 'Checking strategy alignment and consistency...', progress: 75 },
{ type: 'autofill_final_review', message: 'Performing final review and optimization...', progress: 85 },
{ type: 'autofill_complete', message: 'Strategy inputs generation completed successfully...', progress: 95 }
];
let messageIndex = 0;
const transparencyInterval = setInterval(() => {
if (messageIndex < transparencyMessages.length) {
const message = transparencyMessages[messageIndex];
console.log('🎯 Raw Polling Message:', {
type: message.type,
message: message.message,
progress: message.progress,
timestamp: new Date().toISOString()
});
setCurrentPhase(message.type);
addTransparencyMessage(message.message);
setStoreGenerationProgress(message.progress);
setRefreshProgress(message.progress);
messageIndex++;
} else {
clearInterval(transparencyInterval);
}
};
es.onerror = (err: any) => {
console.error('SSE connection error:', err);
es.close();
setAIGenerating(false);
setIsRefreshing(false);
setRefreshError('AI refresh connection lost. Please try again.');
setRefreshMessage('Connection lost.');
};
}, 2000); // Send a message every 2 seconds for better UX
// Call the non-streaming refresh endpoint (Polling-based approach)
console.log('🎯 Calling AI refresh endpoint (Polling-based)...');
const response = await contentPlanningApi.refreshAutofill(1, true, true);
console.log('🎯 Raw Polling Response:', {
success: !!response,
hasData: !!response?.data,
responseStructure: {
hasDataProperty: !!response?.data?.data,
hasFieldsDirect: !!response?.data?.fields,
hasFieldsInData: !!response?.data?.data?.fields
},
fieldsCount: Object.keys(response?.data?.data?.fields || response?.data?.fields || {}).length,
sourcesCount: Object.keys(response?.data?.data?.sources || response?.data?.sources || {}).length,
meta: response?.data?.data?.meta || response?.data?.meta || {},
timestamp: new Date().toISOString()
});
// Clear the transparency interval since we got the response
clearInterval(transparencyInterval);
// Process the response
if (response && response.data) {
// The API response is wrapped in ResponseBuilder format:
// { status: "success", message: "...", data: { fields: {...}, sources: {...}, meta: {...} } }
// So we need to access payload.data.fields, not payload.fields
const payload = response.data;
const fields = payload.data?.fields || payload.fields || {};
const sources = payload.data?.sources || payload.sources || {};
const inputDataPoints = payload.data?.input_data_points || payload.input_data_points || {};
const meta = payload.data?.meta || payload.meta || {};
console.log('🎯 AI Refresh Result - Payload:', payload);
console.log('🎯 AI Refresh Result - Fields:', fields);
console.log('🎯 AI Refresh Result - Meta:', meta);
console.log('🎯 Fields structure check:', {
fieldsType: typeof fields,
fieldsKeys: Object.keys(fields),
sampleField: fields[Object.keys(fields)[0]],
hasValueProperty: fields[Object.keys(fields)[0]]?.hasOwnProperty('value')
});
// 🚨 CRITICAL: Check if AI generation failed
if (meta.error || !meta.ai_used || meta.ai_overrides_count === 0) {
console.error('❌ AI generation failed:', meta.error || 'No AI data generated');
setError(`AI generation failed: ${meta.error || 'No real AI data was generated. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
// 🚨 CRITICAL: Validate data source
if (meta.data_source === 'ai_generation_failed' || meta.data_source === 'ai_generation_error' || meta.data_source === 'ai_disabled') {
console.error('❌ Invalid data source:', meta.data_source);
setError(`AI generation failed: ${meta.error || 'Invalid data source. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
console.log('✅ AI generation successful - processing real AI data');
const fieldValues: Record<string, any> = {};
const confidenceScores: Record<string, number> = {};
Object.keys(fields).forEach((fieldId) => {
const fieldData = fields[fieldId];
console.log(`🎯 Processing field ${fieldId}:`, fieldData);
if (fieldData && typeof fieldData === 'object' && 'value' in fieldData) {
fieldValues[fieldId] = fieldData.value;
console.log(`✅ Field ${fieldId} value extracted:`, fieldData.value);
// Extract confidence score if available
if (fieldData.confidence) {
confidenceScores[fieldId] = fieldData.confidence;
console.log(`🎯 Field ${fieldId} confidence: ${fieldData.confidence}`);
}
// Extract personalization data if available
if (fieldData.personalization_data) {
console.log(`🎯 Field ${fieldId} personalization:`, fieldData.personalization_data);
}
} else {
console.warn(`⚠️ Field ${fieldId} has invalid structure:`, fieldData);
}
});
console.log('🎯 Processed field values:', Object.keys(fieldValues));
console.log('🎯 Confidence scores:', confidenceScores);
console.log('🎯 Field values details:', fieldValues);
// Update the store with the new data
useEnhancedStrategyStore.setState((state) => {
const newState = {
autoPopulatedFields: { ...state.autoPopulatedFields, ...fieldValues },
dataSources: { ...state.dataSources, ...sources },
inputDataPoints: { ...state.inputDataPoints, ...inputDataPoints },
confidenceScores: { ...state.confidenceScores, ...confidenceScores },
formData: { ...state.formData, ...fieldValues }
};
console.log('🎯 Updated store state:', newState);
console.log('🎯 Field values being added:', fieldValues);
console.log('🎯 Confidence scores being added:', confidenceScores);
console.log('🎯 Store autoPopulatedFields count:', Object.keys(newState.autoPopulatedFields).length);
return newState;
});
// Add final completion message
addTransparencyMessage(`✅ AI generation completed successfully! Generated ${Object.keys(fieldValues).length} real AI values.`);
setStoreGenerationProgress(100);
setRefreshProgress(100);
setCurrentPhase('Complete');
setRefreshMessage(`AI refresh completed! Generated ${Object.keys(fieldValues).length} fields.`);
// Close modal after a short delay to show completion
setTimeout(() => {
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
console.log('🎯 Polling-based AI refresh completed successfully!', {
fieldsGenerated: Object.keys(fieldValues).length,
confidenceScoresCount: Object.keys(confidenceScores).length,
dataSourcesCount: Object.keys(sources).length,
approach: 'Polling (No SSE)',
timestamp: new Date().toISOString()
});
}, 2000);
} else {
throw new Error('Invalid response from AI refresh endpoint');
}
} catch (e) {
console.error('AI refresh error', e);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI refresh failed. Please try again.');
setRefreshMessage('Refresh failed.');
setError(`AI refresh failed: ${e instanceof Error ? e.message : 'Unknown error'}`);
}
}}
refreshMessage={refreshMessage}
@@ -469,6 +590,7 @@ const ContentStrategyBuilder: React.FC = () => {
formErrors={formErrors}
autoPopulatedFields={autoPopulatedFields}
dataSources={dataSources}
inputDataPoints={inputDataPoints}
personalizationData={personalizationData}
completionStats={completionStats}
reviewedCategories={reviewedCategories}
@@ -478,7 +600,17 @@ const ContentStrategyBuilder: React.FC = () => {
onUpdateFormField={updateFormField}
onValidateFormField={validateFormField}
onShowTooltip={setShowTooltip}
onViewDataSource={() => setShowDataSourceTransparency(true)}
onViewDataSource={(fieldId) => {
// If a specific field is provided, show field-specific data source info
if (fieldId) {
console.log('🎯 Viewing data source for field:', fieldId);
// For now, just open the general data source transparency modal
// In the future, this could open a field-specific modal
setShowDataSourceTransparency(true);
} else {
setShowDataSourceTransparency(true);
}
}}
onConfirmCategoryReview={handleConfirmCategoryReviewWrapper}
onSetActiveCategory={setActiveCategory}
onSetShowEducationalInfo={setShowEducationalInfo}
@@ -524,8 +656,8 @@ const ContentStrategyBuilder: React.FC = () => {
<EducationalModal
open={showEducationalModal}
onClose={() => setShowEducationalModal(false)}
educationalContent={educationalContent}
generationProgress={generationProgress}
educationalContent={storeEducationalContent}
generationProgress={storeGenerationProgress}
/>
{/* Data Source Transparency Modal */}
@@ -555,6 +687,21 @@ const ContentStrategyBuilder: React.FC = () => {
</DialogActions>
</Dialog>
{/* Strategy Autofill Transparency Modal */}
<StrategyAutofillTransparencyModal
open={transparencyModalOpen}
onClose={() => setTransparencyModalOpen(false)}
autoPopulatedFields={autoPopulatedFields}
dataSources={dataSources}
inputDataPoints={inputDataPoints}
isGenerating={isGenerating}
generationProgress={storeGenerationProgress}
currentPhase={currentPhase}
educationalContent={storeEducationalContent}
transparencyMessages={transparencyMessages}
error={error}
/>
{/* Tooltip */}
{showTooltip && (
<EnhancedTooltip

View File

@@ -25,6 +25,7 @@ import {
import { motion } from 'framer-motion';
import StrategicInputField from '../StrategicInputField';
import { CategoryDetailViewProps, EducationalInfoDialogProps } from '../types/contentStrategy.types';
import { useEnhancedStrategyStore } from '../../../../../stores/enhancedStrategyStore';
const EducationalInfoDialog: React.FC<EducationalInfoDialogProps> = ({
open,
@@ -97,6 +98,7 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
formErrors,
autoPopulatedFields,
dataSources,
inputDataPoints,
personalizationData,
completionStats,
reviewedCategories,
@@ -114,6 +116,8 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
getCategoryColor,
getEducationalContent
}) => {
// Get confidence scores from store
const { confidenceScores } = useEnhancedStrategyStore();
if (!activeCategory) {
return (
<motion.div
@@ -193,13 +197,13 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
error={formErrors[field.id]}
autoPopulated={!!autoPopulatedFields[field.id]}
dataSource={dataSources[field.id]}
confidenceLevel={autoPopulatedFields[field.id] ? 0.8 : undefined}
confidenceLevel={confidenceScores[field.id] || (autoPopulatedFields[field.id] ? 0.8 : undefined)}
dataQuality={autoPopulatedFields[field.id] ? 'High Quality' : undefined}
personalizationData={personalizationData[field.id]}
onChange={(value: any) => onUpdateFormField(field.id, value)}
onValidate={() => onValidateFormField(field.id)}
onShowTooltip={() => onShowTooltip(field.id)}
onViewDataSource={onViewDataSource}
onViewDataSource={() => onViewDataSource(field.id)}
accentColorKey={getCategoryColor(activeCategory) as any}
isCompact={isCompactField}
/>

View File

@@ -26,6 +26,7 @@ export interface CategoryDetailViewProps {
formErrors: Record<string, any>;
autoPopulatedFields: Record<string, any>;
dataSources: Record<string, any>;
inputDataPoints: Record<string, any>;
personalizationData: Record<string, any>;
completionStats: any;
reviewedCategories: Set<string>;
@@ -35,7 +36,7 @@ export interface CategoryDetailViewProps {
onUpdateFormField: (fieldId: string, value: any) => void;
onValidateFormField: (fieldId: string) => boolean;
onShowTooltip: (fieldId: string) => void;
onViewDataSource: () => void;
onViewDataSource: (fieldId?: string) => void;
onConfirmCategoryReview: () => void;
onSetActiveCategory: (category: string | null) => void;
onSetShowEducationalInfo: (categoryId: string | null) => void;

View File

@@ -539,222 +539,29 @@ class ContentPlanningAPI {
}
// 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;
});
}
// SSE Strategy Generation
async streamStrategyGeneration(strategyId: number): Promise<EventSource> {
// The backend endpoint doesn't need strategy_id, it creates the strategy internally
const url = `${this.baseURL}/content-strategy/ai-generation/generate-comprehensive-strategy/stream?user_id=1&strategy_name=Enhanced%20Content%20Strategy`;
console.log('🚀 Creating SSE connection for strategy generation:');
console.log(' URL:', url);
console.log(' Base URL:', this.baseURL);
console.log(' Strategy ID:', strategyId);
const eventSource = new EventSource(url);
// Add comprehensive error handling
eventSource.onerror = (error) => {
console.error('❌ SSE Error in strategy generation:', error);
console.error(' ReadyState:', eventSource.readyState);
console.error(' URL:', url);
// Don't close immediately on error - let the frontend handle it
// eventSource.close();
};
eventSource.onopen = () => {
console.log('✅ SSE connection opened successfully');
console.log(' ReadyState:', eventSource.readyState);
console.log(' URL:', url);
};
eventSource.onmessage = (event) => {
console.log('📨 SSE message received:', event.data);
};
return eventSource;
}
// New polling-based strategy generation methods
async startStrategyGenerationPolling(userId: number = 1, strategyName?: string, config?: any): Promise<any> {
return this.handleRequest(async () => {
const payload = {
user_id: userId,
strategy_name: strategyName || 'Enhanced Content Strategy',
config: config || {}
};
console.log('🚀 Starting polling-based strategy generation:', payload);
const response = await apiClient.post(
`${this.baseURL}/content-strategy/ai-generation/generate-comprehensive-strategy-polling`,
payload
);
console.log('✅ Strategy generation started:', response.data);
return response.data.data || response.data;
});
}
async getStrategyGenerationStatus(taskId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/content-strategy/ai-generation/strategy-generation-status/${taskId}`);
return response.data.data || response.data;
});
}
// Get the latest generated strategy from polling system
async getLatestGeneratedStrategy(userId: number = 1): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/content-strategy/ai-generation/latest-strategy`, {
params: { user_id: userId }
});
return response.data.data || response.data;
});
}
// Polling utility method
async pollStrategyGeneration(
taskId: string,
onProgress: (status: any) => void,
onComplete: (strategy: any) => void,
onError: (error: any) => void,
pollInterval: number = 10000, // 10 seconds
maxAttempts: number = 36 // 6 minutes max (36 * 10 seconds)
): Promise<void> {
let attempts = 0;
const poll = async () => {
try {
attempts++;
console.log(`📊 Polling attempt ${attempts}/${maxAttempts} for task: ${taskId}`);
const status = await this.getStrategyGenerationStatus(taskId);
// Call progress callback
onProgress(status);
// Check if completed
if (status.status === 'completed') {
console.log('✅ Strategy generation completed:', status);
onComplete(status.strategy);
return;
}
// Check if failed
if (status.status === 'failed') {
console.error('❌ Strategy generation failed:', status.error);
onError(status.error || 'Strategy generation failed');
return;
}
// Check if max attempts reached
if (attempts >= maxAttempts) {
console.warn('⏰ Max polling attempts reached, checking final status...');
const finalStatus = await this.getStrategyGenerationStatus(taskId);
if (finalStatus.status === 'completed') {
onComplete(finalStatus.strategy);
} else {
onError('Strategy generation timeout. The process may still be running in the background.');
}
return;
}
// Continue polling
setTimeout(poll, pollInterval);
} catch (error) {
console.error('❌ Error polling strategy generation status:', error);
onError(error);
}
};
// Start polling
poll();
}
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 params: any = {};
if (userId) params.user_id = userId;
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data;
});
}
async getEnhancedStrategy(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}`);
return response.data;
});
}
async createEnhancedStrategy(strategy: any): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies`, strategy);
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`);
@@ -776,22 +583,6 @@ class ContentPlanningAPI {
});
}
// 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);
}
// Clear enhanced strategy streaming/cache for a user (best-effort refresh)
async clearEnhancedCache(userId?: number): Promise<any> {
const params: any = {};
@@ -800,21 +591,7 @@ class ContentPlanningAPI {
return response.data;
}
// Stream AI generation/status updates for a specific strategy (best-effort)
async streamAIGenerationStatus(strategyId: number | string): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/strategies?strategy_id=${strategyId}`;
return new EventSource(url);
}
async streamAutofillRefresh(userId?: number, useAI: boolean = true, aiOnly: boolean = false): Promise<EventSource> {
const params = new URLSearchParams();
if (userId) params.append('user_id', String(userId));
params.append('use_ai', String(useAI));
params.append('ai_only', String(aiOnly));
const url = `${this.baseURL}/enhanced-strategies/autofill/refresh/stream?${params.toString()}`;
return new EventSource(url);
}
// Non-streaming autofill refresh method
async refreshAutofill(userId?: number, useAI: boolean = true, aiOnly: boolean = false): Promise<any> {
const params: any = { use_ai: useAI, ai_only: aiOnly };
if (userId) params.user_id = userId;
@@ -822,7 +599,68 @@ class ContentPlanningAPI {
return response.data;
}
// Helper method to handle SSE data
// Enhanced Strategy CRUD Operations
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;
});
}
// Onboarding Data Methods
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;
});
}
// AI Analysis Methods
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;
});
}
// SSE Methods (for Orchestrator - real-time updates needed)
async streamStrategicIntelligence(userId?: number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/strategic-intelligence?user_id=${userId || 1}`;
return new EventSource(url);
}
// Helper method to handle SSE data (for Orchestrator)
handleSSEData(eventSource: EventSource, onData: (data: any) => void, onError?: (error: any) => void, onComplete?: () => void) {
eventSource.onmessage = (event) => {
try {
@@ -848,6 +686,26 @@ class ContentPlanningAPI {
return eventSource;
}
// Polling and Status Methods
async getLatestGeneratedStrategy(userId?: number): Promise<any> {
return this.handleRequest(async () => {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/latest-generated`, { params });
return response.data;
});
}
// Additional SSE Methods (for other features that need real-time updates)
async streamKeywordResearch(userId?: number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/keyword-research?user_id=${userId || 1}`;
return new EventSource(url);
}
async streamAIGenerationStatus(strategyId: string | number): Promise<EventSource> {
const url = `${this.baseURL}/enhanced-strategies/stream/ai-generation-status?strategy_id=${strategyId}`;
return new EventSource(url);
}
}
// Export singleton instance

View File

@@ -160,6 +160,7 @@ interface EnhancedStrategyStore {
dataSources: Record<string, string>;
inputDataPoints: Record<string, any>; // Detailed input data points from backend
personalizationData: Record<string, any>; // Personalization data for each field
confidenceScores: Record<string, number>; // Confidence scores for each field
// UI State
loading: boolean;
@@ -167,12 +168,29 @@ interface EnhancedStrategyStore {
saving: boolean;
aiGenerating: boolean;
// Transparency State
transparencyModalOpen: boolean;
generationProgress: number;
currentPhase: string;
educationalContent: any;
transparencyMessages: string[];
isGenerating: boolean;
// Actions
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
setSaving: (saving: boolean) => void;
setAIGenerating: (generating: boolean) => void;
// Transparency actions
setTransparencyModalOpen: (open: boolean) => void;
setGenerationProgress: (progress: number) => void;
setCurrentPhase: (phase: string) => void;
setEducationalContent: (content: any) => void;
addTransparencyMessage: (message: string) => void;
clearTransparencyMessages: () => void;
setIsGenerating: (generating: boolean) => void;
// Strategy actions
createEnhancedStrategy: (strategy: Partial<EnhancedStrategy>) => Promise<EnhancedStrategy>;
updateEnhancedStrategy: (id: string, updates: Partial<EnhancedStrategy>) => Promise<void>;
@@ -604,6 +622,7 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
dataSources: {},
inputDataPoints: {}, // Initialize inputDataPoints
personalizationData: {}, // Initialize personalizationData
confidenceScores: {}, // Initialize confidenceScores
// UI State
loading: false,
@@ -611,12 +630,31 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
saving: false,
aiGenerating: false,
// Transparency State
transparencyModalOpen: false,
generationProgress: 0,
currentPhase: '',
educationalContent: null,
transparencyMessages: [],
isGenerating: false,
// Actions
setLoading: (loading) => set({ loading }),
setError: (error) => set({ error }),
setSaving: (saving) => set({ saving }),
setAIGenerating: (generating) => set({ aiGenerating: generating }),
// Transparency actions
setTransparencyModalOpen: (open) => set({ transparencyModalOpen: open }),
setGenerationProgress: (progress) => set({ generationProgress: progress }),
setCurrentPhase: (phase) => set({ currentPhase: phase }),
setEducationalContent: (content) => set({ educationalContent: content }),
addTransparencyMessage: (message) => set((state) => ({
transparencyMessages: [...state.transparencyMessages, message]
})),
clearTransparencyMessages: () => set({ transparencyMessages: [] }),
setIsGenerating: (generating) => set({ isGenerating: generating }),
// Strategy actions
createEnhancedStrategy: async (strategy) => {
set({ saving: true, error: null });
@@ -725,8 +763,16 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
dataSources: {},
inputDataPoints: {}, // Reset inputDataPoints
personalizationData: {}, // Reset personalizationData
confidenceScores: {}, // Reset confidenceScores
currentStep: 0,
completedSteps: []
completedSteps: [],
// Reset transparency state
transparencyModalOpen: false,
generationProgress: 0,
currentPhase: '',
educationalContent: null,
transparencyMessages: [],
isGenerating: false
});
},
@@ -793,6 +839,7 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
const fieldValues: Record<string, any> = {};
const autoPopulatedFields: Record<string, any> = {};
const personalizationData: Record<string, any> = {};
const confidenceScores: Record<string, number> = {}; // Initialize confidenceScores
Object.keys(fields).forEach(fieldId => {
const fieldData = fields[fieldId];
@@ -808,6 +855,12 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
console.log(`🎯 Personalization data for ${fieldId}:`, fieldData.personalization_data);
}
// Extract confidence score if available
if (fieldData.confidence_score) {
confidenceScores[fieldId] = fieldData.confidence_score;
console.log(`💯 Confidence score for ${fieldId}:`, fieldData.confidence_score);
}
console.log(`✅ Auto-populated ${fieldId}:`, fieldData.value);
} else {
console.log(`❌ Skipping ${fieldId} - invalid data structure`);
@@ -817,12 +870,14 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
console.log('📝 Final field values:', fieldValues);
console.log('🔄 Final auto-populated fields:', autoPopulatedFields);
console.log('🎯 Personalization data:', personalizationData);
console.log('💯 Confidence scores:', confidenceScores);
set((state) => ({
autoPopulatedFields,
dataSources: sources,
inputDataPoints, // Store the detailed input data points
personalizationData, // Store personalization data
confidenceScores, // Store confidence scores
formData: { ...state.formData, ...fieldValues }
}));