Add SEO fields to Tasks model, improve content generation response handling, and enhance progress bar animation

- Added primary_keyword, secondary_keywords, tags, and categories fields to Tasks model
- Updated generate_content function to handle full JSON response with all SEO fields
- Improved progress bar animation: smooth 1% increments every 300ms
- Enhanced step detection for content generation vs clustering vs ideas
- Fixed progress modal to show correct messages for each function type
- Added comprehensive logging to Keywords and Tasks pages for AI functions
- Fixed error handling to show meaningful error messages instead of generic failures
This commit is contained in:
Gitea Deploy
2025-11-09 21:22:34 +00:00
parent 09d22ab0e2
commit 961362e088
17340 changed files with 10636 additions and 2248776 deletions

View File

@@ -1049,10 +1049,17 @@ Make sure each prompt is detailed enough for image generation, describing the vi
account=None,
response_steps=None,
progress_callback=None,
tracker=None, # Optional ConsoleStepTracker for logging
**kwargs
) -> Dict[str, Any]:
"""
Cluster keywords using AI-based semantic similarity.
[DEPRECATED] Cluster keywords using AI-based semantic similarity.
⚠️ WARNING: This method is deprecated. Use the new AI framework instead:
- New path: views.py -> run_ai_task -> AIEngine -> AutoClusterFunction
- This method uses the old prompt system and does not use PromptRegistry
- Console logging may not work correctly in this path
Based on reference plugin's clustering prompt.
Args:
@@ -1063,6 +1070,7 @@ Make sure each prompt is detailed enough for image generation, describing the vi
Returns:
Dict with 'clusters' (list of cluster dicts with name, description, keywords)
"""
logger.warning("AIProcessor.cluster_keywords is deprecated. Use the new AI framework (AutoClusterFunction) instead.")
if not keywords:
return {
'clusters': [],
@@ -1075,20 +1083,41 @@ Make sure each prompt is detailed enough for image generation, describing the vi
for kw in keywords
])
if tracker:
tracker.prep(f"Formatted {len(keywords)} keywords for prompt")
account_obj = account or self.account
# Get prompt template from database or default
# NOTE: This is legacy code. New code should use PromptRegistry.get_prompt()
# Keeping this for backward compatibility with old tasks
prompt_template = self.get_prompt('clustering', account=account_obj)
# Replace placeholders in prompt template
if '[IGNY8_KEYWORDS]' not in prompt_template:
error_msg = "Prompt template missing [IGNY8_KEYWORDS] placeholder"
logger.error(error_msg)
if tracker:
tracker.error('Prompt', error_msg)
return {
'clusters': [],
'error': error_msg,
}
prompt = prompt_template.replace('[IGNY8_KEYWORDS]', keywords_text)
if tracker:
tracker.prep(f"Prompt prepared: {len(prompt)} characters (keywords: {len(keywords_text)} chars)")
if sector_name:
prompt += f"\n\nNote: These keywords are for the '{sector_name}' sector."
logger.info(f"Clustering {len(keywords)} keywords using AI")
logger.info(f"AIProcessor.cluster_keywords: About to call OpenAI API with {len(keywords)} keywords")
if tracker:
tracker.ai_call(f"Calling OpenAI API with model: {self.default_model}")
# Initialize response_steps if not provided
if response_steps is None:
response_steps = []
@@ -1109,6 +1138,12 @@ Make sure each prompt is detailed enough for image generation, describing the vi
response_format=response_format,
response_steps=response_steps
)
if tracker:
if result.get('error'):
tracker.error('AI_CALL', f"OpenAI API error: {result['error']}")
else:
tracker.ai_call(f"Received response: {result.get('total_tokens', 0)} tokens")
logger.info(f"AIProcessor.cluster_keywords: OpenAI API call completed. Error: {result.get('error')}, Has content: {bool(result.get('content'))}")
except Exception as e:
logger.error(f"AIProcessor.cluster_keywords: Exception calling OpenAI API: {type(e).__name__}: {str(e)}", exc_info=True)
@@ -1141,11 +1176,16 @@ Make sure each prompt is detailed enough for image generation, describing the vi
}
# Step 11: JSON Extraction & Parsing
if tracker:
tracker.parse("Extracting JSON from AI response")
step_start = time.time()
json_data = self._extract_json_from_response(result['content'])
if not json_data:
logger.error(f"Failed to parse clustering response: {result.get('content', '')[:200]}")
error_msg = f"Failed to parse clustering response: {result.get('content', '')[:200]}"
logger.error(error_msg)
if tracker:
tracker.error('Parse', error_msg)
if response_steps is not None:
response_steps.append({
'stepNumber': 11,
@@ -1194,7 +1234,10 @@ Make sure each prompt is detailed enough for image generation, describing the vi
clusters = json_data
if not clusters:
logger.error(f"No clusters found in response: {json_data}")
error_msg = f"No clusters found in response: {json_data}"
logger.error(error_msg)
if tracker:
tracker.error('Parse', error_msg)
if response_steps is not None:
response_steps.append({
'stepNumber': 12,
@@ -1216,6 +1259,10 @@ Make sure each prompt is detailed enough for image generation, describing the vi
'response_steps': response_steps
}
logger.info(f"Successfully parsed {len(clusters)} clusters from AI response")
if tracker:
tracker.parse(f"Successfully extracted {len(clusters)} clusters from response")
if response_steps is not None:
response_steps.append({
'stepNumber': 12,