Revert "Implement V2 AI functions and enhance progress handling"

This reverts commit e2f2d79d4c.
This commit is contained in:
Desktop
2025-11-10 22:42:08 +05:00
parent e2f2d79d4c
commit f8bbf99df8
12 changed files with 58 additions and 920 deletions

View File

@@ -66,7 +66,7 @@ export default function AIProgressModal({
const modalInstanceId = modalInstanceIdRef.current || 'modal-01';
// Build full function ID with modal instance (only for debugging, not shown in UI)
// Build full function ID with modal instance
const fullFunctionId = functionId ? `${functionId}-${modalInstanceId}` : null;
// Determine color based on status
@@ -201,10 +201,11 @@ export default function AIProgressModal({
</div>
)}
{/* Task ID (for debugging - Function ID not shown per requirements) */}
{taskId && (
{/* Function ID and Task ID (for debugging) */}
{(fullFunctionId || taskId) && (
<div className="mb-6 space-y-1 text-xs text-gray-400 dark:text-gray-600">
<div>Task ID: {taskId}</div>
{fullFunctionId && <div>Function ID: {fullFunctionId}</div>}
{taskId && <div>Task ID: {taskId}</div>}
</div>
)}
@@ -281,10 +282,11 @@ export default function AIProgressModal({
{config.errorMessage || message}
</p>
{/* Task ID (for debugging - Function ID not shown per requirements) */}
{taskId && (
{/* Function ID and Task ID (for debugging) */}
{(fullFunctionId || taskId) && (
<div className="mb-6 space-y-1 text-xs text-gray-400 dark:text-gray-600">
<div>Task ID: {taskId}</div>
{fullFunctionId && <div>Function ID: {fullFunctionId}</div>}
{taskId && <div>Task ID: {taskId}</div>}
</div>
)}
@@ -388,10 +390,15 @@ export default function AIProgressModal({
</div>
)}
{/* Task ID (for debugging - Function ID not shown per requirements) */}
{taskId && (
{/* Function ID and Task ID (for debugging) */}
{(fullFunctionId || taskId) && (
<div className="mb-4 space-y-1 text-xs text-gray-400 dark:text-gray-600">
<div>Task ID: {taskId}</div>
{fullFunctionId && (
<div>Function ID: {fullFunctionId}</div>
)}
{taskId && (
<div>Task ID: {taskId}</div>
)}
</div>
)}

View File

@@ -144,12 +144,6 @@ const tableActionsConfigs: Record<string, TableActionsConfig> = {
icon: <BoltIcon className="w-4 h-4 text-warning-500" />,
variant: 'secondary',
},
{
key: 'keywords_clustering',
label: 'Keywords Clustering',
icon: <BoltIcon className="w-4 h-4 text-brand-500" />,
variant: 'secondary',
},
],
},
'/planner/clusters': {
@@ -166,12 +160,6 @@ const tableActionsConfigs: Record<string, TableActionsConfig> = {
icon: <BoltIcon className="w-5 h-5" />,
variant: 'primary',
},
{
key: 'generate_ideas_v2',
label: 'Generate Ideas V2',
icon: <BoltIcon className="w-5 h-5" />,
variant: 'primary',
},
],
bulkActions: [
{

View File

@@ -232,10 +232,8 @@ export function useProgressModal(): UseProgressModalReturn {
`/v1/system/settings/task_progress/${taskId}/`
);
// Helper function to start auto-increment progress
// 0-50%: 300ms per 1%
// 50-80%: 500ms per 1%
// If stuck at 80%: 1% per 500ms
// Helper function to start auto-increment progress (1% every 350ms until 80%)
// Only runs when no backend updates are coming (smooth fill-in animation)
const startAutoIncrement = () => {
// Clear any existing auto-increment interval
if (autoIncrementIntervalRef.current) {
@@ -243,10 +241,11 @@ export function useProgressModal(): UseProgressModalReturn {
autoIncrementIntervalRef.current = null;
}
// Only start if we're below 100% and status is processing
// Only start if we're below 80% and status is processing
const current = displayedPercentageRef.current;
if (current < 100) {
const doIncrement = () => {
if (current < 80) {
// Use a slightly longer interval to avoid conflicts with backend updates
autoIncrementIntervalRef.current = setInterval(() => {
setProgress(prev => {
// Check current status - stop if not processing
if (prev.status !== 'processing') {
@@ -258,30 +257,17 @@ export function useProgressModal(): UseProgressModalReturn {
}
const currentPercent = displayedPercentageRef.current;
let newPercentage = currentPercent;
let nextInterval = 300; // Default 300ms
if (currentPercent < 50) {
// 0-50%: 300ms per 1%
newPercentage = Math.min(currentPercent + 1, 50);
nextInterval = 300;
} else if (currentPercent < 80) {
// 50-80%: 500ms per 1%
newPercentage = Math.min(currentPercent + 1, 80);
nextInterval = 500;
} else if (currentPercent < 100) {
// Stuck at 80%+: 1% per 500ms
newPercentage = Math.min(currentPercent + 1, 99);
nextInterval = 500;
}
if (newPercentage > currentPercent && newPercentage < 100) {
// Only increment if still below 80%
if (currentPercent < 80) {
const newPercentage = Math.min(currentPercent + 1, 80);
displayedPercentageRef.current = newPercentage;
// Restart interval with new speed if needed
if (autoIncrementIntervalRef.current) {
clearInterval(autoIncrementIntervalRef.current);
autoIncrementIntervalRef.current = setInterval(doIncrement, nextInterval);
// Stop if we've reached 80%
if (newPercentage >= 80) {
if (autoIncrementIntervalRef.current) {
clearInterval(autoIncrementIntervalRef.current);
autoIncrementIntervalRef.current = null;
}
}
return {
@@ -289,7 +275,7 @@ export function useProgressModal(): UseProgressModalReturn {
percentage: newPercentage,
};
} else {
// Stop if we've reached 100% or can't increment
// Stop if we've reached 80%
if (autoIncrementIntervalRef.current) {
clearInterval(autoIncrementIntervalRef.current);
autoIncrementIntervalRef.current = null;
@@ -297,11 +283,7 @@ export function useProgressModal(): UseProgressModalReturn {
return prev;
}
});
};
// Start with appropriate interval based on current percentage
const initialInterval = current < 50 ? 300 : 500;
autoIncrementIntervalRef.current = setInterval(doIncrement, initialInterval);
}, 350); // Slightly longer interval to reduce conflicts
}
};
@@ -405,20 +387,19 @@ export function useProgressModal(): UseProgressModalReturn {
const safeTargetPercentage = Math.max(targetPercentage, currentDisplayedPercentage);
// Smooth progress animation: increment gradually until reaching target
// Speed: 300ms per 1% until 50%, then 500ms per 1%
// Use smaller increments and faster updates for smoother animation
if (safeTargetPercentage > currentDisplayedPercentage) {
// Start smooth animation
let animatedPercentage = currentDisplayedPercentage;
const animateProgress = () => {
if (animatedPercentage < safeTargetPercentage) {
// Always increment by 1%
const increment = 1;
// Calculate increment based on distance for smooth animation
const diff = safeTargetPercentage - animatedPercentage;
// Use smaller increments for smoother feel
// If close (< 5%), increment by 1, otherwise by 2
const increment = diff <= 5 ? 1 : Math.min(2, Math.ceil(diff / 10));
animatedPercentage = Math.min(animatedPercentage + increment, safeTargetPercentage);
displayedPercentageRef.current = animatedPercentage;
// Determine speed based on current percentage
const speed = animatedPercentage < 50 ? 300 : 500; // 300ms until 50%, then 500ms
setProgress({
percentage: animatedPercentage,
message: friendlyMessage,
@@ -433,17 +414,13 @@ export function useProgressModal(): UseProgressModalReturn {
});
if (animatedPercentage < safeTargetPercentage) {
// Use appropriate speed based on current percentage
const nextSpeed = animatedPercentage < 50 ? 300 : 500;
stepTransitionTimeoutRef.current = setTimeout(animateProgress, nextSpeed);
// Smooth updates: 150ms for better UX
stepTransitionTimeoutRef.current = setTimeout(animateProgress, 150);
} else {
stepTransitionTimeoutRef.current = null;
// After reaching target, start auto-increment if below 80% and no backend update pending
if (safeTargetPercentage < 80) {
startAutoIncrement();
} else if (safeTargetPercentage >= 80 && safeTargetPercentage < 100) {
// If at 80%+, start slow auto-increment (1% per 500ms)
startAutoIncrement();
}
}
}
@@ -458,8 +435,7 @@ export function useProgressModal(): UseProgressModalReturn {
} else {
// Same step or first step - start animation immediately
currentStepRef.current = currentStep;
const initialSpeed = currentDisplayedPercentage < 50 ? 300 : 500;
stepTransitionTimeoutRef.current = setTimeout(animateProgress, initialSpeed);
animateProgress();
}
} else {
// Target is same or less than current - just update message and details
@@ -479,9 +455,6 @@ export function useProgressModal(): UseProgressModalReturn {
// Start auto-increment if below 80% and no backend update
if (currentDisplayedPercentage < 80 && safeTargetPercentage === currentDisplayedPercentage) {
startAutoIncrement();
} else if (currentDisplayedPercentage >= 80 && currentDisplayedPercentage < 100) {
// If at 80%+, start slow auto-increment (1% per 500ms)
startAutoIncrement();
}
}
@@ -554,61 +527,26 @@ export function useProgressModal(): UseProgressModalReturn {
} else if (response.state === 'SUCCESS') {
const meta = response.meta || {};
// Clear any existing transition timeout and auto-increment
// Clear any existing transition timeout
if (stepTransitionTimeoutRef.current) {
clearTimeout(stepTransitionTimeoutRef.current);
stepTransitionTimeoutRef.current = null;
}
if (autoIncrementIntervalRef.current) {
clearInterval(autoIncrementIntervalRef.current);
autoIncrementIntervalRef.current = null;
}
// Get completion message with extracted values
const completionMessage = meta.message || '';
const allSteps = [...(meta.request_steps || []), ...(meta.response_steps || [])];
const stepInfo = getStepInfo('DONE', completionMessage, allSteps);
// Smooth completion animation: 5% per 500ms until 100%
const currentPercent = displayedPercentageRef.current;
if (currentPercent < 100) {
const animateToCompletion = () => {
const current = displayedPercentageRef.current;
if (current < 100) {
const increment = Math.min(5, 100 - current); // 5% per step, or remaining if less
const newPercentage = current + increment;
displayedPercentageRef.current = newPercentage;
setProgress({
percentage: newPercentage,
message: stepInfo.friendlyMessage,
status: 'completed',
details: meta.details,
});
if (newPercentage < 100) {
stepTransitionTimeoutRef.current = setTimeout(animateToCompletion, 500);
} else {
currentStepRef.current = 'DONE';
}
} else {
currentStepRef.current = 'DONE';
}
};
currentStepRef.current = 'DONE';
animateToCompletion();
} else {
// Already at 100%, just update message and status
currentStepRef.current = 'DONE';
displayedPercentageRef.current = 100;
setProgress({
percentage: 100,
message: stepInfo.friendlyMessage,
status: 'completed',
details: meta.details,
});
}
// Update to 100% with user-friendly completion message
currentStepRef.current = 'DONE';
displayedPercentageRef.current = 100;
setProgress({
percentage: 100,
message: stepInfo.friendlyMessage,
status: 'completed',
details: meta.details,
});
// Update final step logs
if (meta.request_steps || meta.response_steps) {

View File

@@ -13,7 +13,6 @@ import {
bulkDeleteClusters,
bulkUpdateClustersStatus,
autoGenerateIdeas,
generateIdeasV2,
Cluster,
ClusterFilters,
ClusterCreateData,
@@ -219,22 +218,6 @@ export default function Clusters() {
} catch (error: any) {
toast.error(`Failed to generate ideas: ${error.message}`);
}
} else if (action === 'generate_ideas_v2') {
try {
const result = await generateIdeasV2([row.id]);
if (result.success && result.task_id) {
// Async task - show progress modal
progressModal.openModal(result.task_id, 'Generate Ideas', 'ai_generate_ideas_v2');
} else if (result.success) {
toast.success(result.message || 'Ideas generated successfully');
await loadClusters();
} else {
toast.error(result.error || 'Failed to generate ideas');
}
} catch (error: any) {
toast.error(`Failed to generate ideas: ${error.message}`);
}
}
}, [toast, progressModal, loadClusters]);

View File

@@ -20,7 +20,6 @@ import {
Cluster,
API_BASE_URL,
autoClusterKeywords,
autoClusterKeywordsV2,
fetchSeedKeywords,
SeedKeyword,
} from '../../services/api';
@@ -449,35 +448,6 @@ export default function Keywords() {
}]);
toast.error(errorMsg);
}
} else if (action === 'keywords_clustering') {
if (ids.length === 0) {
toast.error('Please select at least one keyword');
return;
}
if (ids.length > 50) {
toast.error('Maximum 50 keywords allowed for clustering');
return;
}
const numIds = ids.map(id => parseInt(id));
const sectorId = activeSector?.id;
try {
const result = await autoClusterKeywordsV2(numIds, sectorId);
if (result.success && result.task_id) {
// Async task - open progress modal
hasReloadedRef.current = false;
progressModal.openModal(result.task_id, 'Keywords Clustering', 'ai_auto_cluster_v2');
} else if (result.success) {
toast.success(result.message || 'Clustering completed');
await loadKeywords();
} else {
toast.error(result.error || 'Clustering failed');
}
} catch (error: any) {
toast.error(`Clustering failed: ${error.message}`);
}
} else {
toast.info(`Bulk action "${action}" for ${ids.length} items`);
}

View File

@@ -807,140 +807,6 @@ export async function autoGenerateIdeas(clusterIds: number[]): Promise<{ success
}
}
export async function autoClusterKeywordsV2(keywordIds: number[], sectorId?: number): Promise<{ success: boolean; task_id?: string; clusters_created?: number; keywords_updated?: number; message?: string; error?: string }> {
const startTime = Date.now();
const addLog = useAIRequestLogsStore.getState().addLog;
const endpoint = `/v1/planner/keywords/auto_cluster_v2/`;
const requestBody = { ids: keywordIds, sector_id: sectorId };
const pendingLogId = addLog({
function: 'autoClusterKeywordsV2',
endpoint,
request: {
method: 'POST',
body: requestBody,
},
status: 'pending',
});
try {
const response = await fetchAPI(endpoint, {
method: 'POST',
body: JSON.stringify(requestBody),
});
const duration = Date.now() - startTime;
const updateLog = useAIRequestLogsStore.getState().updateLog;
if (pendingLogId && response) {
updateLog(pendingLogId, {
response: {
status: 200,
data: response,
},
status: response.success === false ? 'error' : 'success',
duration,
});
}
if (response && response.success === false) {
return response;
}
return response;
} catch (error: any) {
const duration = Date.now() - startTime;
const updateLog = useAIRequestLogsStore.getState().updateLog;
let errorMessage = error.message || 'Unknown error';
if (pendingLogId) {
updateLog(pendingLogId, {
response: {
status: 500,
error: errorMessage,
},
status: 'error',
duration,
});
}
return {
success: false,
error: errorMessage,
};
}
}
export async function generateIdeasV2(clusterIds: number[]): Promise<{ success: boolean; task_id?: string; ideas_created?: number; message?: string; error?: string }> {
const startTime = Date.now();
const { useAIRequestLogsStore } = await import('../store/aiRequestLogsStore').catch(() => ({ useAIRequestLogsStore: null }));
const addLog = useAIRequestLogsStore?.getState().addLog;
const endpoint = `/v1/planner/clusters/generate_ideas_v2/`;
const requestBody = { ids: clusterIds };
addLog?.({
function: 'generateIdeasV2',
endpoint,
request: {
method: 'POST',
body: requestBody,
},
status: 'pending',
});
try {
const response = await fetchAPI(endpoint, {
method: 'POST',
body: JSON.stringify(requestBody),
});
const duration = Date.now() - startTime;
addLog?.({
function: 'generateIdeasV2',
endpoint,
request: {
method: 'POST',
body: requestBody,
},
response: {
status: 200,
data: response,
},
status: 'success',
duration,
});
return response;
} catch (error: any) {
const duration = Date.now() - startTime;
let errorMessage = error.message || 'Unknown error';
addLog?.({
function: 'generateIdeasV2',
endpoint,
request: {
method: 'POST',
body: requestBody,
},
response: {
status: 500,
error: errorMessage,
},
status: 'error',
duration,
});
return {
success: false,
error: errorMessage,
};
}
}
export async function generateSingleIdea(ideaId: string | number, clusterId: number): Promise<{ success: boolean; task_id?: string; idea_created?: number; message?: string; error?: string }> {
const startTime = Date.now();
const { useAIRequestLogsStore } = await import('../store/aiRequestLogsStore').catch(() => ({ useAIRequestLogsStore: null }));