Files
igny8/IGNY8_AI_SYSTEM_AUDIT_BASELINE_REPORT.md
Desktop ecbab4d380 audits
2025-11-10 23:04:12 +05:00

772 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`, and `ConsoleStepTracker`
- **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 from `IntegrationSettings`
- **`_load_account_settings()`** - Loads OpenAI/Runware API keys and model from `IntegrationSettings` or Django settings
- **`get_api_key(integration_type='openai')`** - Returns API key for integration type
- **`get_model(integration_type='openai')`** - Returns model name for integration type
- **`run_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 logging
- **`extract_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 generation
- **`calculate_cost(model, input_tokens, output_tokens, model_type='text')`** - Calculates API cost
- **`call_openai(...)`** - **LEGACY** - Redirects to `run_ai_request()`
#### `AIEngine` (engine.py)
- **`__init__(celery_task=None, account=None)`** - Initialize with Celery task and account
- **`execute(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 to `AITaskLog` model
- **`_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:
1. Task-level `prompt_override` (if exists)
2. DB prompt for (account, function)
3. Default fallback from registry
- **`_render_prompt(prompt_template, context)`** - Renders template with `[IGNY8_*]` placeholders and `{variable}` format
- **`get_image_prompt_template(account=None)`** - Gets image prompt template
- **`get_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 exist
- **`prepare(payload, account=None)`** - Loads keywords with relationships
- **`build_prompt(data, account=None)`** - Builds clustering prompt using `PromptRegistry`
- **`parse_response(response, step_tracker=None)`** - Parses JSON cluster data
- **`save_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 exist
- **`prepare(payload, account=None)`** - Loads clusters with keywords
- **`build_prompt(data, account=None)`** - Builds ideas generation prompt
- **`parse_response(response, step_tracker=None)`** - Parses JSON ideas data
- **`save_output(parsed, original_data, account=None, ...)`** - Creates `ContentIdeas` records
#### `GenerateContentFunction` (functions/generate_content.py)
- **`get_name()`** - Returns `'generate_content'`
- **`validate(payload, account=None)`** - Validates task IDs exist
- **`prepare(payload, account=None)`** - Loads tasks with relationships
- **`build_prompt(data, account=None)`** - Builds content generation prompt
- **`parse_response(response, step_tracker=None)`** - Parses JSON or plain text content
- **`save_output(parsed, original_data, account=None, ...)`** - Saves content to `Content` model
#### `GenerateImagesFunction` (functions/generate_images.py)
- **`get_name()`** - Returns `'generate_images'`
- **`validate(payload, account=None)`** - Validates task IDs exist
- **`prepare(payload, account=None)`** - Loads tasks and image settings
- **`build_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, ...)`** - Creates `Images` records
### 2.3 Tracking Functions
#### `StepTracker` (tracker.py)
- **`add_request_step(step_name, status='success', message='', error=None, duration=None)`** - Adds request step
- **`add_response_step(step_name, status='success', message='', error=None, duration=None)`** - Adds response step
- **`get_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 state
- **`set_phase(phase, percentage, message, meta=None)`** - Sets progress phase
- **`complete(message='Task complete!', meta=None)`** - Marks task as complete
- **`error(error_message, meta=None)`** - Marks task as failed
- **`get_duration()`** - Returns elapsed time in milliseconds
#### `ConsoleStepTracker` (tracker.py)
- **`init(message='Task started')`** - Logs initialization
- **`prep(message)`** - Logs preparation phase
- **`ai_call(message)`** - Logs AI call phase
- **`parse(message)`** - Logs parsing phase
- **`save(message)`** - Logs save phase
- **`done(message='Execution completed')`** - Logs completion
- **`error(error_type, message, exception=None)`** - Logs error
- **`retry(attempt, max_attempts, reason='')`** - Logs retry
- **`timeout(timeout_seconds)`** - Logs timeout
- **`rate_limit(retry_after)`** - Logs rate limit
- **`malformed_json(details='')`** - Logs JSON parsing error
#### `CostTracker` (tracker.py)
- **`record(function_name, cost, tokens, model=None)`** - Records API call cost
- **`get_total()`** - Returns total cost
- **`get_total_tokens()`** - Returns total tokens
- **`get_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 via `AIEngine`
#### Legacy Tasks (modules/*/tasks.py)
- **`auto_cluster_keywords_task`** (planner/tasks.py) - **DEPRECATED** - Uses old `AIProcessor`
- **`auto_generate_content_task`** (writer/tasks.py) - Uses `AIProcessor` directly (not via framework)
- **`auto_generate_images_task`** (writer/tasks.py) - Uses `AIProcessor` directly
### 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 of `AICore.extract_json()`)
- **`generate_content(prompt, model=None, max_tokens=4000, temperature=0.7, **kwargs)`** - Generates text content
- **`extract_image_prompts(content, title, max_images=3, account=None)`** - Extracts image prompts from content
- **`check_moderation(text, api_key=None)`** - Checks content moderation
- **`generate_image(prompt, provider='openai', model=None, size='1024x1024', n=1, api_key=None, **kwargs)`** - Generates images
- **`cluster_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.py` uses `app.autodiscover_tasks()` to auto-discover tasks from all Django apps
- Tasks are registered via `@shared_task` decorator
**Registered Tasks:**
1. `ai.tasks.run_ai_task` - Unified entrypoint (NEW)
2. `planner.tasks.auto_cluster_keywords_task` - **DEPRECATED**
3. `writer.tasks.auto_generate_content_task` - Legacy (still active)
4. `writer.tasks.auto_generate_images_task` - Legacy (still active)
**Task State Management:**
- `ProgressTracker.update()` calls `task.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 by `AIEngine._log_to_database()`)
- `IntegrationSettings` - API keys and model configuration (used by `AICore._load_account_settings()`)
- `AIPrompt` - Custom prompt templates (used by `PromptRegistry.get_prompt()`)
**Data Models:**
- `Keywords` - Input for clustering
- `Clusters` - Output of clustering
- `ContentIdeas` - Output of idea generation
- `Tasks` - Input for content/image generation
- `Content` - Output of content generation
- `Images` - Output of image generation
### 6.3 Frontend API Integration
**Endpoints:**
1. `POST /v1/planner/keywords/auto_cluster/``planner.views.ClusterViewSet.auto_cluster()`
- Calls `run_ai_task.delay(function_name='auto_cluster', ...)`
2. `POST /v1/planner/clusters/auto_generate_ideas/``planner.views.ClusterViewSet.auto_generate_ideas()`
- Calls `run_ai_task.delay(function_name='auto_generate_ideas', ...)`
3. `POST /v1/writer/tasks/auto_generate_content/``writer.views.TasksViewSet.auto_generate_content()`
- Calls `auto_generate_content_task.delay(...)` [LEGACY PATH]
4. `POST /v1/writer/tasks/auto_generate_images/``writer.views.TasksViewSet.auto_generate_images()`
- Calls `auto_generate_images_task.delay(...)` [LEGACY PATH]
**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_steps` and `response_steps` from task meta
### 6.4 Configuration Integration
**Settings Loading Hierarchy:**
1. **Account-level** (`IntegrationSettings` model):
- API keys: `IntegrationSettings.config['apiKey']`
- Model: `IntegrationSettings.config['model']`
- Image settings: `IntegrationSettings.config` (for image_generation type)
2. **Django Settings** (fallback):
- `OPENAI_API_KEY`
- `RUNWARE_API_KEY`
- `DEFAULT_AI_MODEL`
3. **Function-level** (`ai/settings.py`):
- `MODEL_CONFIG[function_name]` - Default model, max_tokens, temperature per function
**Prompt Loading Hierarchy:**
1. Task-level override: `task.prompt_override` (if exists)
2. Account-level: `AIPrompt` model (account, prompt_type)
3. Default: `PromptRegistry.DEFAULT_PROMPTS[prompt_type]`
### 6.5 Debug Panel Integration
**Console Logging:**
- `ConsoleStepTracker` logs to stdout/stderr (only if `DEBUG_MODE=True`)
- Logs include timestamps, phases, messages, errors
**Step Tracking:**
- `StepTracker` maintains `request_steps` and `response_steps` arrays
- Steps include: `stepNumber`, `stepName`, `status`, `message`, `duration`, `error`
- Steps are included in Celery task meta and displayed in progress modal
**Database Logging:**
- `AITaskLog` records 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_steps` parameter instead of `tracker`
- 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()` and `get_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 `IntegrationSettings` if account provided
- Falls back to `MODEL_CONFIG` defaults
**Location 2:** `ai/ai_core.py::_load_account_settings()` (lines 46-90)
- Reads model from `IntegrationSettings` directly
- Similar logic but embedded in `AICore.__init__()`
**Location 3:** `utils/ai_processor.py::_get_model()` (lines 98-123)
- Reads model from `IntegrationSettings` directly
- 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``BaseAIFunction` implementations
- Legacy: Direct `AIProcessor` calls in `modules/*/tasks.py`
**Potential Action:** Gradually migrate all legacy tasks to use the new framework. Mark legacy code as deprecated.
---
## 9. Assumptions Made
1. **File `wordpress.py`** was not read - assumed to be unrelated to AI processing based on name.
2. **Frontend code** was partially analyzed via search results - full frontend audit not performed.
3. **Database migrations** were not analyzed - assumed to be standard Django migrations.
4. **Test files** were not analyzed - `ai/tests/test_run.py` exists but was not read.
5. **Settings file** (`backend/igny8_core/settings.py`) was not read - assumed to contain standard Django settings.
6. **System module utilities** (`modules/system/utils.py`) were referenced but not fully read - assumed to contain `get_prompt_value()` and `get_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
1. **Template Method Pattern:** `BaseAIFunction` defines algorithm skeleton, subclasses implement steps
2. **Registry Pattern:** `FunctionRegistry` for dynamic function discovery
3. **Factory Pattern:** `get_function_instance()` creates function instances
4. **Strategy Pattern:** Different AI functions implement same interface
5. **Observer Pattern:** `ProgressTracker` updates Celery task state
6. **Facade Pattern:** `AICore` provides simplified interface to OpenAI/Runware APIs
---
**End of Report**