34 KiB
IGNY8 AI System Audit — Current Structure & Flow Mapping (Baseline Report)
Date: 2024-12-19
Scope: Complete structural and functional audit of the IGNY8 AI subsystem
Methodology: Code analysis without modifications or assumptions
Executive Summary
The IGNY8 AI subsystem is a comprehensive framework for AI-powered content operations including keyword clustering, idea generation, content generation, and image generation. The system uses a unified framework architecture with a centralized execution engine, but also maintains legacy code paths for backward compatibility.
Key Findings:
- 20 core AI files in
backend/igny8_core/ai/ - 4 AI function implementations following BaseAIFunction pattern
- Dual execution paths: New unified framework (
run_ai_task→AIEngine) and legacy paths (direct task calls) - Centralized AI request handling via
AICore.run_ai_request() - Comprehensive tracking via
StepTracker,ProgressTracker,CostTracker, andConsoleStepTracker - Multiple prompt management systems:
PromptRegistry(new) and direct database queries (legacy)
1. Current File Inventory
1.1 Core AI Framework (backend/igny8_core/ai/)
| File | Lines | Purpose |
|---|---|---|
__init__.py |
73 | Package exports - exposes main classes and functions |
admin.py |
60 | Django admin configuration for AITaskLog model |
ai_core.py |
756 | Centralized AI request handler - AICore class with run_ai_request() and generate_image() |
apps.py |
21 | Django app configuration |
base.py |
95 | Abstract base class BaseAIFunction - defines function interface |
constants.py |
42 | Model pricing, valid models, configuration constants |
engine.py |
375 | Central orchestrator AIEngine - manages function lifecycle |
models.py |
52 | Database model AITaskLog for unified logging |
processor.py |
76 | DEPRECATED wrapper around AICore for backward compatibility |
prompts.py |
432 | PromptRegistry - centralized prompt management with hierarchical resolution |
registry.py |
97 | Function registry with lazy loading - register_function(), get_function() |
settings.py |
117 | Model configurations per function - MODEL_CONFIG, get_model_config() |
tasks.py |
131 | Unified Celery task entrypoint run_ai_task() - single entry point for all AI functions |
tracker.py |
348 | Progress tracking utilities - StepTracker, ProgressTracker, CostTracker, ConsoleStepTracker |
types.py |
44 | Type definitions - StepLog, ProgressState, AITaskResult dataclasses |
validators.py |
187 | Validation functions - validate_ids(), validate_keywords_exist(), etc. |
1.2 AI Function Implementations (backend/igny8_core/ai/functions/)
| File | Lines | Purpose |
|---|---|---|
__init__.py |
18 | Function package exports |
auto_cluster.py |
330 | AutoClusterFunction - Groups keywords into semantic clusters |
generate_content.py |
388 | GenerateContentFunction + generate_content_core() - Generates article content |
generate_ideas.py |
335 | GenerateIdeasFunction + generate_ideas_core() - Generates content ideas from clusters |
generate_images.py |
279 | GenerateImagesFunction + generate_images_core() - Generates images for tasks |
1.3 Utility Files (backend/igny8_core/utils/)
| File | Lines | Purpose |
|---|---|---|
ai_processor.py |
1407 | LEGACY Unified AI interface - AIProcessor class with OpenAI/Runware support. Contains duplicate constants and methods. |
content_normalizer.py |
273 | Content normalization - converts AI responses to HTML format |
queue_manager.py |
90 | Queue abstraction (currently placeholder, not fully implemented) |
wordpress.py |
(not read) | WordPress integration utilities |
1.4 Module Task Files
| File | Lines | Purpose |
|---|---|---|
modules/planner/tasks.py |
736 | DEPRECATED Legacy clustering task auto_cluster_keywords_task() - uses old AIProcessor |
modules/writer/tasks.py |
1156 | Legacy content/image generation tasks - auto_generate_content_task(), auto_generate_images_task() |
1.5 Configuration Files
| File | Purpose |
|---|---|
celery.py |
Celery app configuration - auto-discovers tasks from all Django apps |
modules/system/models.py |
AIPrompt, IntegrationSettings models for AI configuration |
2. Function Inventory
2.1 Core Framework Functions
AICore (ai_core.py)
__init__(account=None)- Initialize with account context, loads API keys and model fromIntegrationSettings_load_account_settings()- Loads OpenAI/Runware API keys and model fromIntegrationSettingsor Django settingsget_api_key(integration_type='openai')- Returns API key for integration typeget_model(integration_type='openai')- Returns model name for integration typerun_ai_request(prompt, model=None, max_tokens=4000, temperature=0.7, response_format=None, api_key=None, function_name='ai_request', function_id=None, tracker=None)- CENTRAL METHOD - Handles all OpenAI text generation requests with console loggingextract_json(response_text)- Extracts JSON from response text (handles markdown code blocks)generate_image(prompt, provider='openai', model=None, size='1024x1024', n=1, api_key=None, negative_prompt=None, function_name='generate_image')- Generates images via OpenAI DALL-E or Runware_generate_image_openai(...)- Internal method for OpenAI image generation_generate_image_runware(...)- Internal method for Runware image generationcalculate_cost(model, input_tokens, output_tokens, model_type='text')- Calculates API costcall_openai(...)- LEGACY - Redirects torun_ai_request()
AIEngine (engine.py)
__init__(celery_task=None, account=None)- Initialize with Celery task and accountexecute(fn: BaseAIFunction, payload: dict)- CENTRAL ORCHESTRATOR - Unified execution pipeline:- Phase 1: INIT (0-10%) - Validation
- Phase 2: PREP (10-25%) - Data loading & prompt building
- Phase 3: AI_CALL (25-70%) - API call to provider
- Phase 4: PARSE (70-85%) - Response parsing
- Phase 5: SAVE (85-98%) - Database operations
- Phase 6: DONE (98-100%) - Finalization
_handle_error(error, fn=None, exc_info=False)- Centralized error handling_log_to_database(fn, payload, parsed, save_result, error=None)- Logs toAITaskLogmodel_calculate_credits_for_clustering(keyword_count, tokens, cost)- Calculates credits for clustering operations
PromptRegistry (prompts.py)
get_prompt(function_name, account=None, task=None, context=None)- Hierarchical prompt resolution:- Task-level
prompt_override(if exists) - DB prompt for (account, function)
- Default fallback from registry
- Task-level
_render_prompt(prompt_template, context)- Renders template with[IGNY8_*]placeholders and{variable}formatget_image_prompt_template(account=None)- Gets image prompt templateget_negative_prompt(account=None)- Gets negative prompt
BaseAIFunction (base.py) - Abstract Interface
get_name()- Returns function name (abstract)get_metadata()- Returns function metadata (display name, description, phases)validate(payload, account=None)- Validates input payload (default: checks for 'ids')get_max_items()- Returns max items limit (optional)prepare(payload, account=None)- Loads and prepares data (abstract)build_prompt(data, account=None)- Builds AI prompt (abstract)get_model(account=None)- Returns model override (optional)parse_response(response, step_tracker=None)- Parses AI response (abstract)save_output(parsed, original_data, account=None, progress_tracker=None, step_tracker=None)- Saves results to database (abstract)
2.2 AI Function Implementations
AutoClusterFunction (functions/auto_cluster.py)
get_name()- Returns'auto_cluster'validate(payload, account=None)- Validates keyword IDs existprepare(payload, account=None)- Loads keywords with relationshipsbuild_prompt(data, account=None)- Builds clustering prompt usingPromptRegistryparse_response(response, step_tracker=None)- Parses JSON cluster datasave_output(parsed, original_data, account=None, ...)- Creates/updates clusters and assigns keywords
GenerateIdeasFunction (functions/generate_ideas.py)
get_name()- Returns'generate_ideas'validate(payload, account=None)- Validates cluster IDs existprepare(payload, account=None)- Loads clusters with keywordsbuild_prompt(data, account=None)- Builds ideas generation promptparse_response(response, step_tracker=None)- Parses JSON ideas datasave_output(parsed, original_data, account=None, ...)- CreatesContentIdeasrecords
GenerateContentFunction (functions/generate_content.py)
get_name()- Returns'generate_content'validate(payload, account=None)- Validates task IDs existprepare(payload, account=None)- Loads tasks with relationshipsbuild_prompt(data, account=None)- Builds content generation promptparse_response(response, step_tracker=None)- Parses JSON or plain text contentsave_output(parsed, original_data, account=None, ...)- Saves content toContentmodel
GenerateImagesFunction (functions/generate_images.py)
get_name()- Returns'generate_images'validate(payload, account=None)- Validates task IDs existprepare(payload, account=None)- Loads tasks and image settingsbuild_prompt(data, account=None)- Extracts image prompts from task content (calls AI)parse_response(response, step_tracker=None)- Returns parsed response (already parsed)save_output(parsed, original_data, account=None, ...)- CreatesImagesrecords
2.3 Tracking Functions
StepTracker (tracker.py)
add_request_step(step_name, status='success', message='', error=None, duration=None)- Adds request stepadd_response_step(step_name, status='success', message='', error=None, duration=None)- Adds response stepget_meta()- Returns metadata dict with request/response steps
ProgressTracker (tracker.py)
update(phase, percentage, message, current=None, total=None, current_item=None, meta=None)- Updates Celery task stateset_phase(phase, percentage, message, meta=None)- Sets progress phasecomplete(message='Task complete!', meta=None)- Marks task as completeerror(error_message, meta=None)- Marks task as failedget_duration()- Returns elapsed time in milliseconds
ConsoleStepTracker (tracker.py)
init(message='Task started')- Logs initializationprep(message)- Logs preparation phaseai_call(message)- Logs AI call phaseparse(message)- Logs parsing phasesave(message)- Logs save phasedone(message='Execution completed')- Logs completionerror(error_type, message, exception=None)- Logs errorretry(attempt, max_attempts, reason='')- Logs retrytimeout(timeout_seconds)- Logs timeoutrate_limit(retry_after)- Logs rate limitmalformed_json(details='')- Logs JSON parsing error
CostTracker (tracker.py)
record(function_name, cost, tokens, model=None)- Records API call costget_total()- Returns total costget_total_tokens()- Returns total tokensget_operations()- Returns all operations list
2.4 Celery Tasks
run_ai_task (ai/tasks.py)
run_ai_task(self, function_name: str, payload: dict, account_id: int = None)- UNIFIED ENTRYPOINT - Dynamically loads and executes AI functions viaAIEngine
Legacy Tasks (modules/*/tasks.py)
auto_cluster_keywords_task(planner/tasks.py) - DEPRECATED - Uses oldAIProcessorauto_generate_content_task(writer/tasks.py) - UsesAIProcessordirectly (not via framework)auto_generate_images_task(writer/tasks.py) - UsesAIProcessordirectly
2.5 Legacy Functions (ai_processor.py)
AIProcessor - LEGACY/DEPRECATED
_call_openai(prompt, model=None, max_tokens=4000, temperature=0.7, response_format=None, api_key=None, function_id=None, response_steps=None)- Internal OpenAI API caller_extract_json_from_response(response_text)- JSON extraction (duplicate ofAICore.extract_json())generate_content(prompt, model=None, max_tokens=4000, temperature=0.7, **kwargs)- Generates text contentextract_image_prompts(content, title, max_images=3, account=None)- Extracts image prompts from contentcheck_moderation(text, api_key=None)- Checks content moderationgenerate_image(prompt, provider='openai', model=None, size='1024x1024', n=1, api_key=None, **kwargs)- Generates imagescluster_keywords(keywords, sector_name=None, account=None, response_steps=None, progress_callback=None, tracker=None, **kwargs)- DEPRECATED - Clusters keywords (old method)generate_ideas(clusters, account=None, **kwargs)- Generates ideas (old method)get_prompt(prompt_type, account=None)- Gets prompt from database (old method)estimate_cost(operation, tokens_or_prompt, model=None)- Estimates cost (not implemented)
3. Class Inventory
3.1 Core Classes
| Class | File | Purpose | Inheritance |
|---|---|---|---|
AICore |
ai_core.py | Centralized AI request handler | - |
AIEngine |
engine.py | Central orchestrator for AI functions | - |
BaseAIFunction |
base.py | Abstract base for all AI functions | ABC |
PromptRegistry |
prompts.py | Centralized prompt management | - |
StepTracker |
tracker.py | Tracks request/response steps | - |
ProgressTracker |
tracker.py | Tracks Celery progress updates | - |
CostTracker |
tracker.py | Tracks API costs and tokens | - |
ConsoleStepTracker |
tracker.py | Console-based step logging | - |
AITaskLog |
models.py | Database model for AI task logging | AccountBaseModel |
AIProcessor |
utils/ai_processor.py | LEGACY Unified AI interface | - |
3.2 Function Classes
| Class | File | Purpose | Inheritance |
|---|---|---|---|
AutoClusterFunction |
functions/auto_cluster.py | Keyword clustering | BaseAIFunction |
GenerateIdeasFunction |
functions/generate_ideas.py | Idea generation | BaseAIFunction |
GenerateContentFunction |
functions/generate_content.py | Content generation | BaseAIFunction |
GenerateImagesFunction |
functions/generate_images.py | Image generation | BaseAIFunction |
3.3 Data Classes
| Class | File | Purpose |
|---|---|---|
StepLog |
types.py | Single step in request/response tracking |
ProgressState |
types.py | Progress state for AI tasks |
AITaskResult |
types.py | Result from AI function execution |
4. Dependency Graph/Table
4.1 Import Relationships
ai/__init__.py
├─> registry.py (register_function, get_function, list_functions)
├─> engine.py (AIEngine)
├─> base.py (BaseAIFunction)
├─> ai_core.py (AICore)
├─> validators.py (all validators)
├─> constants.py (all constants)
├─> prompts.py (PromptRegistry, get_prompt)
└─> settings.py (MODEL_CONFIG, get_model_config, etc.)
ai/tasks.py
├─> engine.py (AIEngine)
└─> registry.py (get_function_instance)
ai/engine.py
├─> base.py (BaseAIFunction)
├─> tracker.py (StepTracker, ProgressTracker, CostTracker, ConsoleStepTracker)
├─> ai_core.py (AICore)
└─> settings.py (get_model_config)
ai/ai_core.py
├─> constants.py (MODEL_RATES, IMAGE_MODEL_RATES, etc.)
└─> tracker.py (ConsoleStepTracker)
ai/functions/auto_cluster.py
├─> base.py (BaseAIFunction)
├─> ai_core.py (AICore)
├─> prompts.py (PromptRegistry)
└─> settings.py (get_model_config)
ai/functions/generate_content.py
├─> base.py (BaseAIFunction)
├─> ai_core.py (AICore)
├─> prompts.py (PromptRegistry)
└─> settings.py (get_model_config)
ai/functions/generate_ideas.py
├─> base.py (BaseAIFunction)
├─> ai_core.py (AICore)
├─> prompts.py (PromptRegistry)
└─> settings.py (get_model_config)
ai/functions/generate_images.py
├─> base.py (BaseAIFunction)
├─> ai_core.py (AICore)
├─> prompts.py (PromptRegistry)
└─> settings.py (get_model_config)
utils/ai_processor.py
├─> modules/system/models.py (IntegrationSettings)
└─> modules/system/utils.py (get_prompt_value, get_default_prompt)
modules/planner/tasks.py
└─> utils/ai_processor.py (AIProcessor) [DEPRECATED PATH]
modules/writer/tasks.py
├─> utils/ai_processor.py (AIProcessor) [LEGACY PATH]
└─> ai/functions/generate_content.py (generate_content_core)
4.2 External Dependencies
| Dependency | Used By | Purpose |
|---|---|---|
django |
All files | Django ORM, models, settings |
celery |
tasks.py, engine.py | Async task execution |
requests |
ai_core.py, ai_processor.py | HTTP requests to OpenAI/Runware APIs |
json |
Multiple files | JSON parsing |
re |
ai_core.py, ai_processor.py, content_normalizer.py | Regex for JSON extraction |
logging |
All files | Logging |
time |
tracker.py, ai_core.py | Timing and duration tracking |
bs4 (BeautifulSoup) |
content_normalizer.py | HTML parsing (optional) |
4.3 Database Models Dependencies
| Model | Used By | Purpose |
|---|---|---|
AITaskLog |
engine.py | Unified AI task logging |
IntegrationSettings |
ai_core.py, ai_processor.py, settings.py | API keys and model configuration |
AIPrompt |
prompts.py | Custom prompt templates |
Keywords |
auto_cluster.py, validators.py | Keyword data |
Clusters |
auto_cluster.py, generate_ideas.py | Cluster data |
ContentIdeas |
generate_ideas.py | Content ideas |
Tasks |
generate_content.py, generate_images.py | Writer tasks |
Content |
generate_content.py | Generated content |
Images |
generate_images.py | Generated images |
5. System Flow Description
5.1 New Unified Framework Flow (Recommended Path)
Frontend API Call
↓
ViewSet Action (e.g., planner/views.py::auto_cluster)
↓
run_ai_task.delay(function_name='auto_cluster', payload={ids: [...]}, account_id=123)
↓
Celery Worker: run_ai_task (ai/tasks.py)
├─> Load Account
├─> get_function_instance('auto_cluster') → AutoClusterFunction
└─> AIEngine.execute(AutoClusterFunction, payload)
├─> Phase 1: INIT (0-10%)
│ └─> fn.validate(payload, account)
├─> Phase 2: PREP (10-25%)
│ ├─> fn.prepare(payload, account) → Load keywords
│ └─> fn.build_prompt(data, account) → PromptRegistry.get_prompt()
├─> Phase 3: AI_CALL (25-70%)
│ ├─> AICore.run_ai_request(prompt, model, ...)
│ │ ├─> Load API key from IntegrationSettings
│ │ ├─> Validate model
│ │ ├─> Build OpenAI request
│ │ ├─> Send HTTP request
│ │ ├─> Parse response
│ │ └─> Calculate cost
│ └─> Track cost via CostTracker
├─> Phase 4: PARSE (70-85%)
│ └─> fn.parse_response(response_content, step_tracker)
├─> Phase 5: SAVE (85-98%)
│ └─> fn.save_output(parsed, original_data, account, ...)
│ └─> Database transaction: Create/update clusters
└─> Phase 6: DONE (98-100%)
├─> Log to AITaskLog
└─> Return result dict
↓
Celery Task State Update (SUCCESS/FAILURE)
↓
Frontend Polls Task Status
↓
Progress Modal Displays Steps
5.2 Legacy Content Generation Flow (Still Active)
Frontend API Call
↓
ViewSet Action (writer/views.py::auto_generate_content)
↓
auto_generate_content_task.delay(task_ids, account_id)
↓
Celery Worker: auto_generate_content_task (modules/writer/tasks.py)
├─> Load Tasks from database
├─> For each task:
│ ├─> Load prompt template (get_prompt_value)
│ ├─> Format prompt with task data
│ ├─> AIProcessor.generate_content(prompt)
│ │ └─> AIProcessor._call_openai() [DUPLICATE OF AICore.run_ai_request]
│ ├─> Parse response (GenerateContentFunction.parse_response)
│ └─> Save content (GenerateContentFunction.save_output)
└─> Return result
5.3 Legacy Clustering Flow (Deprecated)
Frontend API Call
↓
ViewSet Action (planner/views.py::auto_cluster) [OLD PATH]
↓
_auto_cluster_keywords_core() (modules/planner/tasks.py)
├─> Load keywords
├─> AIProcessor.cluster_keywords() [DEPRECATED]
│ └─> AIProcessor._call_openai() [DUPLICATE]
├─> Parse clusters
└─> Save to database
5.4 Image Generation Flow
Frontend API Call
↓
ViewSet Action (writer/views.py::auto_generate_images)
↓
auto_generate_images_task.delay(task_ids, account_id)
↓
Celery Worker: auto_generate_images_task (modules/writer/tasks.py)
├─> Load tasks
├─> For each task:
│ ├─> Extract image prompts (AIProcessor.extract_image_prompts)
│ │ └─> Calls AI to extract prompts from content
│ ├─> Generate featured image (AIProcessor.generate_image)
│ ├─> Generate desktop images (if enabled)
│ └─> Generate mobile images (if enabled)
└─> Save Images records
6. Integration Points
6.1 Celery Integration
Task Registration:
celery.pyusesapp.autodiscover_tasks()to auto-discover tasks from all Django apps- Tasks are registered via
@shared_taskdecorator
Registered Tasks:
ai.tasks.run_ai_task- Unified entrypoint (NEW)planner.tasks.auto_cluster_keywords_task- DEPRECATEDwriter.tasks.auto_generate_content_task- Legacy (still active)writer.tasks.auto_generate_images_task- Legacy (still active)
Task State Management:
ProgressTracker.update()callstask.update_state(state='PROGRESS', meta={...})- Progress metadata includes:
phase,percentage,message,request_steps,response_steps - Final states:
SUCCESS,FAILURE
6.2 Database Integration
Models:
AITaskLog- Unified logging table (used byAIEngine._log_to_database())IntegrationSettings- API keys and model configuration (used byAICore._load_account_settings())AIPrompt- Custom prompt templates (used byPromptRegistry.get_prompt())
Data Models:
Keywords- Input for clusteringClusters- Output of clusteringContentIdeas- Output of idea generationTasks- Input for content/image generationContent- Output of content generationImages- Output of image generation
6.3 Frontend API Integration
Endpoints:
-
POST /v1/planner/keywords/auto_cluster/→planner.views.ClusterViewSet.auto_cluster()- Calls
run_ai_task.delay(function_name='auto_cluster', ...)
- Calls
-
POST /v1/planner/clusters/auto_generate_ideas/→planner.views.ClusterViewSet.auto_generate_ideas()- Calls
run_ai_task.delay(function_name='auto_generate_ideas', ...)
- Calls
-
POST /v1/writer/tasks/auto_generate_content/→writer.views.TasksViewSet.auto_generate_content()- Calls
auto_generate_content_task.delay(...)[LEGACY PATH]
- Calls
-
POST /v1/writer/tasks/auto_generate_images/→writer.views.TasksViewSet.auto_generate_images()- Calls
auto_generate_images_task.delay(...)[LEGACY PATH]
- Calls
Response Format:
- Success:
{success: true, task_id: "...", message: "..."} - Error:
{success: false, error: "..."}
Progress Tracking:
- Frontend polls Celery task status via
GET /v1/system/tasks/{task_id}/status/ - Progress modal displays
request_stepsandresponse_stepsfrom task meta
6.4 Configuration Integration
Settings Loading Hierarchy:
-
Account-level (
IntegrationSettingsmodel):- API keys:
IntegrationSettings.config['apiKey'] - Model:
IntegrationSettings.config['model'] - Image settings:
IntegrationSettings.config(for image_generation type)
- API keys:
-
Django Settings (fallback):
OPENAI_API_KEYRUNWARE_API_KEYDEFAULT_AI_MODEL
-
Function-level (
ai/settings.py):MODEL_CONFIG[function_name]- Default model, max_tokens, temperature per function
Prompt Loading Hierarchy:
- Task-level override:
task.prompt_override(if exists) - Account-level:
AIPromptmodel (account, prompt_type) - Default:
PromptRegistry.DEFAULT_PROMPTS[prompt_type]
6.5 Debug Panel Integration
Console Logging:
ConsoleStepTrackerlogs to stdout/stderr (only ifDEBUG_MODE=True)- Logs include timestamps, phases, messages, errors
Step Tracking:
StepTrackermaintainsrequest_stepsandresponse_stepsarrays- Steps include:
stepNumber,stepName,status,message,duration,error - Steps are included in Celery task meta and displayed in progress modal
Database Logging:
AITaskLogrecords all AI task executions- Fields:
task_id,function_name,phase,status,cost,tokens,request_steps,response_steps,error,payload,result
7. Identified Redundancies or Repetition
7.1 Duplicate Constants
Location 1: ai/constants.py
MODEL_RATES,IMAGE_MODEL_RATES,VALID_OPENAI_IMAGE_MODELS,VALID_SIZES_BY_MODEL,DEFAULT_AI_MODEL,JSON_MODE_MODELS
Location 2: utils/ai_processor.py (lines 18-44)
- EXACT DUPLICATE of all constants from
constants.py
Impact: Constants are defined in two places, risking inconsistency.
7.2 Duplicate JSON Extraction Logic
Location 1: ai/ai_core.py::extract_json() (lines 391-429)
- Handles markdown code blocks, multiline JSON, direct JSON
Location 2: utils/ai_processor.py::_extract_json_from_response() (lines 342-449)
- MORE COMPREHENSIVE - handles more edge cases, balanced brace matching
Impact: Two implementations with different capabilities. ai_processor.py version is more robust.
7.3 Duplicate OpenAI API Calling Logic
Location 1: ai/ai_core.py::run_ai_request() (lines 106-389)
- Centralized method with console logging via
ConsoleStepTracker - Handles validation, model selection, cost calculation
- Returns standardized dict format
Location 2: utils/ai_processor.py::_call_openai() (lines 125-340)
- SIMILAR LOGIC but with
response_stepsparameter instead oftracker - Less comprehensive error handling
- Different return format
Impact: Two code paths for the same operation. New code should use AICore.run_ai_request().
7.4 Duplicate Image Generation Logic
Location 1: ai/ai_core.py::generate_image() + _generate_image_openai() + _generate_image_runware() (lines 431-728)
- Uses
print()statements for logging (inconsistent with console tracker)
Location 2: utils/ai_processor.py::generate_image() (lines 667-1043)
- MORE COMPREHENSIVE - extensive logging, better error handling
- Handles Runware authentication flow
Impact: Two implementations. ai_processor.py version has better logging.
7.5 Duplicate Prompt Loading Logic
Location 1: ai/prompts.py::PromptRegistry.get_prompt() (lines 280-333)
- Hierarchical resolution: task override → DB prompt → default
- Supports
[IGNY8_*]placeholders and{variable}format
Location 2: utils/ai_processor.py::get_prompt() (lines 1044-1057)
- Simple database lookup via
modules/system/utils.get_prompt_value() - No hierarchical resolution
Location 3: Direct calls in modules/writer/tasks.py (lines 343, 959, 964)
- Uses
get_prompt_value()andget_default_prompt()directly
Impact: Three different ways to load prompts. New code should use PromptRegistry.
7.6 Duplicate Model Configuration Logic
Location 1: ai/settings.py::get_model_config() (lines 49-97)
- Reads from
IntegrationSettingsif account provided - Falls back to
MODEL_CONFIGdefaults
Location 2: ai/ai_core.py::_load_account_settings() (lines 46-90)
- Reads model from
IntegrationSettingsdirectly - Similar logic but embedded in
AICore.__init__()
Location 3: utils/ai_processor.py::_get_model() (lines 98-123)
- Reads model from
IntegrationSettingsdirectly - Similar logic but embedded in
AIProcessor.__init__()
Impact: Model loading logic duplicated in three places.
7.7 Duplicate API Key Loading Logic
Location 1: ai/ai_core.py::_load_account_settings() (lines 46-90)
- Loads OpenAI and Runware keys from
IntegrationSettings
Location 2: utils/ai_processor.py::_get_api_key() (lines 73-96)
- EXACT SAME LOGIC for loading API keys
Impact: Identical code in two places.
7.8 Repeated Error Handling Patterns
Pattern: Multiple files have similar try/except blocks for:
- API request errors
- JSON parsing errors
- Database errors
- Validation errors
Impact: Error handling is not centralized, making it harder to maintain consistent error messages and logging.
7.9 Repeated Progress Update Patterns
Pattern: Multiple places manually build progress update dicts:
modules/writer/tasks.py(lines 62-73, 220-231, etc.)modules/planner/tasks.py(lines 59-71, 203-215, etc.)ai/engine.py(lines 57, 79, 141, etc.)
Impact: Progress update format is not standardized, though ProgressTracker exists to handle this.
8. Summary of Potential Consolidation Areas
8.1 Constants Consolidation
Observation: Model rates, valid models, and configuration constants are duplicated between ai/constants.py and utils/ai_processor.py.
Potential Action: Remove constants from ai_processor.py and import from constants.py. However, ai_processor.py is marked as legacy, so this may not be necessary if it's being phased out.
8.2 JSON Extraction Consolidation
Observation: Two JSON extraction methods exist with different capabilities. ai_processor.py::_extract_json_from_response() is more comprehensive.
Potential Action: Enhance AICore.extract_json() with logic from ai_processor.py, or create a shared utility function.
8.3 API Request Consolidation
Observation: AICore.run_ai_request() and AIProcessor._call_openai() perform the same operation with different interfaces.
Potential Action: All new code should use AICore.run_ai_request(). Legacy code in ai_processor.py can remain for backward compatibility but should be marked as deprecated.
8.4 Image Generation Consolidation
Observation: Two image generation implementations exist. ai_processor.py version has better logging.
Potential Action: Enhance AICore.generate_image() with logging improvements from ai_processor.py, or migrate all code to use AICore.generate_image().
8.5 Prompt Loading Consolidation
Observation: Three different methods exist for loading prompts: PromptRegistry.get_prompt(), AIProcessor.get_prompt(), and direct get_prompt_value() calls.
Potential Action: Migrate all code to use PromptRegistry.get_prompt() for consistency. Update legacy code paths gradually.
8.6 Model/API Key Loading Consolidation
Observation: Model and API key loading logic is duplicated in AICore, AIProcessor, and settings.py.
Potential Action: Create shared utility functions for loading settings from IntegrationSettings, used by all classes.
8.7 Error Handling Consolidation
Observation: Error handling patterns are repeated across multiple files.
Potential Action: Create centralized error handling utilities or enhance AIEngine._handle_error() to be more reusable.
8.8 Progress Tracking Consolidation
Observation: Some code manually builds progress update dicts instead of using ProgressTracker.
Potential Action: Migrate all progress updates to use ProgressTracker.update() for consistency.
8.9 Legacy Code Path Elimination
Observation: Multiple execution paths exist:
- New:
run_ai_task→AIEngine→BaseAIFunctionimplementations - Legacy: Direct
AIProcessorcalls inmodules/*/tasks.py
Potential Action: Gradually migrate all legacy tasks to use the new framework. Mark legacy code as deprecated.
9. Assumptions Made
-
File
wordpress.pywas not read - assumed to be unrelated to AI processing based on name. -
Frontend code was partially analyzed via search results - full frontend audit not performed.
-
Database migrations were not analyzed - assumed to be standard Django migrations.
-
Test files were not analyzed -
ai/tests/test_run.pyexists but was not read. -
Settings file (
backend/igny8_core/settings.py) was not read - assumed to contain standard Django settings. -
System module utilities (
modules/system/utils.py) were referenced but not fully read - assumed to containget_prompt_value()andget_default_prompt()functions.
10. Appendix
10.1 File Line Counts
| Directory | Files | Total Lines |
|---|---|---|
ai/ |
15 | ~2,500 |
ai/functions/ |
5 | ~1,300 |
utils/ (AI-related) |
3 | ~1,800 |
modules/planner/tasks.py |
1 | 736 |
modules/writer/tasks.py |
1 | 1,156 |
| Total | 25 | ~7,500 |
10.2 Function Count Summary
- Core Framework Functions: ~30
- AI Function Implementations: 4 classes × ~6 methods = ~24 methods
- Tracking Functions: ~20
- Legacy Functions: ~15
- Celery Tasks: 4
- Total: ~90 functions/methods
10.3 Key Design Patterns
- Template Method Pattern:
BaseAIFunctiondefines algorithm skeleton, subclasses implement steps - Registry Pattern:
FunctionRegistryfor dynamic function discovery - Factory Pattern:
get_function_instance()creates function instances - Strategy Pattern: Different AI functions implement same interface
- Observer Pattern:
ProgressTrackerupdates Celery task state - Facade Pattern:
AICoreprovides simplified interface to OpenAI/Runware APIs
End of Report