DOCS
This commit is contained in:
45
README.md
45
README.md
@@ -81,39 +81,50 @@ docker-compose -f docker-compose.app.yml up
|
|||||||
|
|
||||||
### ✅ Implemented
|
### ✅ Implemented
|
||||||
- **Foundation**: Multi-tenancy system, Authentication (login/register), RBAC permissions
|
- **Foundation**: Multi-tenancy system, Authentication (login/register), RBAC permissions
|
||||||
- **Planner Module**: Keywords & Clusters (full CRUD, filtering, pagination, bulk operations, CSV import/export)
|
- **Planner Module**: Keywords, Clusters, Content Ideas (full CRUD, filtering, pagination, bulk operations, CSV import/export)
|
||||||
|
- **Writer Module**: Tasks, Content, Images (full CRUD, content generation, image generation)
|
||||||
|
- **Thinker Module**: Prompts, Author Profiles, Strategies, Image Testing
|
||||||
|
- **System Module**: Settings, Integrations (OpenAI, Runware), AI Prompts
|
||||||
|
- **Billing Module**: Credits, Transactions, Usage Logs
|
||||||
|
- **AI Functions**: 5 AI operations (Auto Cluster, Generate Ideas, Generate Content, Generate Image Prompts, Generate Images)
|
||||||
- **Frontend**: Complete component library, 4 master templates, config-driven UI system
|
- **Frontend**: Complete component library, 4 master templates, config-driven UI system
|
||||||
- **Backend**: REST API with tenant isolation, Site > Sector hierarchy
|
- **Backend**: REST API with tenant isolation, Site > Sector hierarchy, Celery async tasks
|
||||||
- **Development**: Docker Compose setup, hot reload, TypeScript + React
|
- **Development**: Docker Compose setup, hot reload, TypeScript + React
|
||||||
|
|
||||||
### 🚧 In Progress
|
### 🚧 In Progress
|
||||||
- Content Ideas module (backend + frontend)
|
|
||||||
- AI integration for auto-clustering and idea generation
|
|
||||||
- Planner Dashboard enhancement with KPIs
|
- Planner Dashboard enhancement with KPIs
|
||||||
|
- WordPress integration (publishing)
|
||||||
|
- Automation & CRON tasks
|
||||||
|
|
||||||
### 🔄 Planned
|
### 🔄 Planned
|
||||||
- Writer module (Tasks, Drafts, Published)
|
- Analytics module enhancements
|
||||||
- Thinker module (Prompts, Strategies, Image Testing)
|
- Advanced scheduling features
|
||||||
- AI Pipeline infrastructure
|
- Additional AI model integrations
|
||||||
- WordPress integration
|
|
||||||
- Automation & CRON tasks
|
|
||||||
|
|
||||||
## 🔗 API Endpoints
|
## 🔗 API Endpoints
|
||||||
|
|
||||||
- **Keywords**: `/api/planner/keywords/`
|
- **Planner**: `/api/v1/planner/keywords/`, `/api/v1/planner/clusters/`, `/api/v1/planner/ideas/`
|
||||||
|
- **Writer**: `/api/v1/writer/tasks/`, `/api/v1/writer/images/`
|
||||||
|
- **System**: `/api/v1/system/settings/`
|
||||||
|
- **Billing**: `/api/v1/billing/`
|
||||||
- **Admin**: `/admin/`
|
- **Admin**: `/admin/`
|
||||||
|
|
||||||
|
See `docs/04-BACKEND.md` for complete API reference.
|
||||||
|
|
||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
All documentation is consolidated in the `/docs/` folder:
|
All documentation is consolidated in the `/docs/` folder. Start with `docs/README.md` for the complete documentation index.
|
||||||
|
|
||||||
- **`docs/01-ARCHITECTURE.md`** - System architecture, design patterns, and key principles
|
### Core Documentation
|
||||||
- **`docs/02-IMPLEMENTATION-ROADMAP.md`** - Complete build roadmap with 21 phases
|
- **`docs/README.md`** - Documentation index and navigation
|
||||||
- **`docs/03-CURRENT-STATUS.md`** - Current progress, completed items, and next steps
|
- **`docs/01-ARCHITECTURE-TECH-STACK.md`** - Technology stack and system architecture
|
||||||
- **`docs/04-API-REFERENCE.md`** - API endpoints reference guide
|
- **`docs/02-APP-ARCHITECTURE.md`** - Application architecture with complete workflows
|
||||||
- **`docs/05-WP-MIGRATION-MAP.md`** - WordPress plugin to Django app migration reference
|
- **`docs/03-FRONTEND.md`** - Complete frontend documentation
|
||||||
|
- **`docs/04-BACKEND.md`** - Complete backend documentation
|
||||||
|
- **`docs/05-AI-FUNCTIONS.md`** - Complete AI functions documentation
|
||||||
|
- **`docs/06-CHANGELOG.md`** - System changelog
|
||||||
|
|
||||||
**Quick Start**: Read `docs/03-CURRENT-STATUS.md` for current state, then `docs/02-IMPLEMENTATION-ROADMAP.md` for what to build next.
|
**Quick Start**: Read `docs/README.md` for navigation, then start with `docs/01-ARCHITECTURE-TECH-STACK.md` for system overview.
|
||||||
|
|
||||||
## 🛠️ Development
|
## 🛠️ Development
|
||||||
|
|
||||||
|
|||||||
476
docs/01-ARCHITECTURE-TECH-STACK.md
Normal file
476
docs/01-ARCHITECTURE-TECH-STACK.md
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
# IGNY8 Architecture & Technology Stack
|
||||||
|
|
||||||
|
**Last Updated:** 2025-01-XX
|
||||||
|
**Purpose:** Complete technology stack and architecture overview for the IGNY8 platform.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Executive Summary](#executive-summary)
|
||||||
|
2. [Technology Stack](#technology-stack)
|
||||||
|
3. [System Architecture](#system-architecture)
|
||||||
|
4. [Core Architecture Principles](#core-architecture-principles)
|
||||||
|
5. [Infrastructure Components](#infrastructure-components)
|
||||||
|
6. [External Service Integrations](#external-service-integrations)
|
||||||
|
7. [Deployment Architecture](#deployment-architecture)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
**IGNY8** is a full-stack SaaS platform for SEO keyword management and AI-driven content generation. The system is built with modern technologies and follows a multi-tenant architecture with complete account isolation.
|
||||||
|
|
||||||
|
### Key Metrics
|
||||||
|
|
||||||
|
- **Architecture**: Multi-tenant SaaS with account isolation
|
||||||
|
- **Backend**: Django 5.2+ with Django REST Framework
|
||||||
|
- **Frontend**: React 19 with TypeScript
|
||||||
|
- **Database**: PostgreSQL 15
|
||||||
|
- **Task Queue**: Celery with Redis
|
||||||
|
- **Deployment**: Docker-based containerization
|
||||||
|
- **Reverse Proxy**: Caddy (HTTPS termination)
|
||||||
|
- **AI Functions**: 5 primary AI operations
|
||||||
|
- **Modules**: 4 core modules (Planner, Writer, System, Billing)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
### Backend Stack
|
||||||
|
|
||||||
|
| Component | Technology | Version | Purpose |
|
||||||
|
|-----------|------------|---------|---------|
|
||||||
|
| **Framework** | Django | 5.2+ | Web framework |
|
||||||
|
| **API Framework** | Django REST Framework | Latest | RESTful API |
|
||||||
|
| **Database** | PostgreSQL | 15 | Primary database |
|
||||||
|
| **Task Queue** | Celery | Latest | Asynchronous tasks |
|
||||||
|
| **Cache/Broker** | Redis | 7 | Celery broker & caching |
|
||||||
|
| **Authentication** | JWT | SimpleJWT | Token-based auth |
|
||||||
|
| **HTTP Client** | Requests | Latest | External API calls |
|
||||||
|
| **WSGI Server** | Gunicorn | Latest | Production server |
|
||||||
|
|
||||||
|
### Frontend Stack
|
||||||
|
|
||||||
|
| Component | Technology | Version | Purpose |
|
||||||
|
|-----------|------------|---------|---------|
|
||||||
|
| **Framework** | React | 19 | UI library |
|
||||||
|
| **Language** | TypeScript | Latest | Type safety |
|
||||||
|
| **Build Tool** | Vite | Latest | Build tool & dev server |
|
||||||
|
| **Styling** | Tailwind CSS | Latest | Utility-first CSS |
|
||||||
|
| **State Management** | Zustand | Latest | Lightweight state |
|
||||||
|
| **Routing** | React Router | v6 | Client-side routing |
|
||||||
|
| **HTTP Client** | Fetch API | Native | API communication |
|
||||||
|
|
||||||
|
### Infrastructure Stack
|
||||||
|
|
||||||
|
| Component | Technology | Purpose |
|
||||||
|
|-----------|------------|---------|
|
||||||
|
| **Containerization** | Docker | Application containers |
|
||||||
|
| **Orchestration** | Docker Compose | Multi-container orchestration |
|
||||||
|
| **Reverse Proxy** | Caddy | HTTPS termination & routing |
|
||||||
|
| **Database Admin** | pgAdmin | PostgreSQL administration |
|
||||||
|
| **File Management** | FileBrowser | Web-based file management |
|
||||||
|
| **Container Management** | Portainer | Docker container management |
|
||||||
|
|
||||||
|
### External Services
|
||||||
|
|
||||||
|
| Service | Purpose | Integration |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| **OpenAI API** | Text generation (GPT models) | API integration |
|
||||||
|
| **OpenAI DALL-E** | Image generation | API integration |
|
||||||
|
| **Runware API** | Alternative image generation | API integration |
|
||||||
|
| **WordPress** | Content publishing | REST API integration |
|
||||||
|
| **Stripe** | Payment processing | Webhook integration (planned) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Architecture
|
||||||
|
|
||||||
|
### High-Level Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Client Layer │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ Browser │ │ Mobile │ │ Admin │ │
|
||||||
|
│ │ (React) │ │ (Future) │ │ Panel │ │
|
||||||
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||||||
|
└─────────┼──────────────────┼──────────────────┼─────────────┘
|
||||||
|
│ │ │
|
||||||
|
└──────────────────┼──────────────────┘
|
||||||
|
│
|
||||||
|
┌────────────────────────────┼──────────────────────────────┐
|
||||||
|
│ Reverse Proxy Layer │
|
||||||
|
│ ┌───────────────┐ │
|
||||||
|
│ │ Caddy │ │
|
||||||
|
│ │ (HTTPS/443) │ │
|
||||||
|
│ └───────┬───────┘ │
|
||||||
|
└────────────────────────────┼──────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌────────────────────────────┼──────────────────────────────┐
|
||||||
|
│ Application Layer │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ Frontend │ │ Backend │ │
|
||||||
|
│ │ (React) │◄─────────────┤ (Django) │ │
|
||||||
|
│ │ Port 8021 │ REST API │ Port 8011 │ │
|
||||||
|
│ └──────────────┘ └──────┬───────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌────────┴────────┐ │
|
||||||
|
│ │ Celery Worker │ │
|
||||||
|
│ │ (Async Tasks) │ │
|
||||||
|
│ └────────┬────────┘ │
|
||||||
|
└───────────────────────────────────────┼──────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────────────────────┼──────────────────┐
|
||||||
|
│ Data Layer │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ PostgreSQL │ │ Redis │ │ Storage │ │
|
||||||
|
│ │ (Database) │ │ (Cache/Broker)│ │ (Files) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────────────────────┼──────────────────┐
|
||||||
|
│ External Services │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ OpenAI │ │ Runware │ │ WordPress │ │
|
||||||
|
│ │ (GPT/DALL-E)│ │ (Images) │ │ (Publish) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. User Request
|
||||||
|
↓
|
||||||
|
2. Browser (React Frontend)
|
||||||
|
↓
|
||||||
|
3. Caddy Reverse Proxy (HTTPS Termination)
|
||||||
|
↓
|
||||||
|
4. Django Backend (API Endpoint)
|
||||||
|
↓
|
||||||
|
5. AccountContextMiddleware (Account Isolation)
|
||||||
|
↓
|
||||||
|
6. ViewSet (Business Logic)
|
||||||
|
↓
|
||||||
|
7. Serializer (Validation)
|
||||||
|
↓
|
||||||
|
8. Model (Database)
|
||||||
|
↓
|
||||||
|
9. Response (JSON)
|
||||||
|
↓
|
||||||
|
10. Frontend (UI Update)
|
||||||
|
```
|
||||||
|
|
||||||
|
### AI Task Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. User Action (e.g., "Auto Cluster Keywords")
|
||||||
|
↓
|
||||||
|
2. Frontend API Call
|
||||||
|
↓
|
||||||
|
3. Backend Endpoint (ViewSet Action)
|
||||||
|
↓
|
||||||
|
4. Celery Task Queued
|
||||||
|
↓
|
||||||
|
5. Task ID Returned to Frontend
|
||||||
|
↓
|
||||||
|
6. Frontend Polls Progress Endpoint
|
||||||
|
↓
|
||||||
|
7. Celery Worker Processes Task
|
||||||
|
↓
|
||||||
|
8. AIProcessor Makes API Calls
|
||||||
|
↓
|
||||||
|
9. Results Saved to Database
|
||||||
|
↓
|
||||||
|
10. Progress Updates Sent
|
||||||
|
↓
|
||||||
|
11. Frontend Displays Results
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Architecture Principles
|
||||||
|
|
||||||
|
### 1. Configuration-Driven Everything
|
||||||
|
|
||||||
|
**Principle**: Zero HTML/JSX duplication - All UI rendered from configuration.
|
||||||
|
|
||||||
|
**Implementation**:
|
||||||
|
- **Frontend**: Config files in `/config/pages/` and `/config/snippets/`
|
||||||
|
- **Backend**: DRF serializers and ViewSet actions
|
||||||
|
- **Templates**: 4 universal templates (Dashboard, Table, Form, System)
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- Single source of truth
|
||||||
|
- Easy maintenance
|
||||||
|
- Consistent UI/UX
|
||||||
|
- Rapid feature development
|
||||||
|
|
||||||
|
### 2. Multi-Tenancy Foundation
|
||||||
|
|
||||||
|
**Principle**: Complete account isolation with automatic filtering.
|
||||||
|
|
||||||
|
**Implementation**:
|
||||||
|
- All models inherit `AccountBaseModel`
|
||||||
|
- All ViewSets inherit `AccountModelViewSet`
|
||||||
|
- Middleware injects account context from JWT
|
||||||
|
- Site > Sector hierarchy for content organization
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- Data security
|
||||||
|
- Scalability
|
||||||
|
- Resource isolation
|
||||||
|
- Simplified access control
|
||||||
|
|
||||||
|
### 3. Template System (4 Universal Templates)
|
||||||
|
|
||||||
|
**Principle**: Reusable templates for all page types.
|
||||||
|
|
||||||
|
| Template | Purpose | Usage |
|
||||||
|
|----------|---------|-------|
|
||||||
|
| **DashboardTemplate** | Module home pages | KPIs, workflow steps, charts |
|
||||||
|
| **TablePageTemplate** | CRUD table pages | Keywords, Clusters, Tasks, etc. |
|
||||||
|
| **FormPageTemplate** | Settings/form pages | Settings, Integration, etc. |
|
||||||
|
| **SystemPageTemplate** | System/admin pages | Logs, Status, Monitoring |
|
||||||
|
|
||||||
|
### 4. Unified AI Processor
|
||||||
|
|
||||||
|
**Principle**: Single interface for all AI operations.
|
||||||
|
|
||||||
|
**Implementation**:
|
||||||
|
- Single `AIEngine` class orchestrates all AI operations
|
||||||
|
- All AI functions inherit from `BaseAIFunction`
|
||||||
|
- Manual and automated workflows use same functions
|
||||||
|
- Account-specific API keys and model configuration
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- Code reusability
|
||||||
|
- Consistent error handling
|
||||||
|
- Unified logging
|
||||||
|
- Easy to extend
|
||||||
|
|
||||||
|
### 5. Module-Based Organization
|
||||||
|
|
||||||
|
**Principle**: Clear module boundaries with shared utilities.
|
||||||
|
|
||||||
|
**Modules**:
|
||||||
|
- **Planner**: Keywords, Clusters, Ideas
|
||||||
|
- **Writer**: Tasks, Content, Images
|
||||||
|
- **System**: Settings, Prompts, Integration
|
||||||
|
- **Billing**: Credits, Transactions, Usage
|
||||||
|
- **Auth**: Accounts, Users, Sites, Sectors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Infrastructure Components
|
||||||
|
|
||||||
|
### Docker Architecture
|
||||||
|
|
||||||
|
The system uses a two-stack Docker architecture:
|
||||||
|
|
||||||
|
1. **Infrastructure Stack (`igny8-infra`)**: Shared services
|
||||||
|
2. **Application Stack (`igny8-app`)**: Application-specific services
|
||||||
|
|
||||||
|
### Infrastructure Stack Services
|
||||||
|
|
||||||
|
| Service | Container Name | Port | Purpose |
|
||||||
|
|---------|----------------|------|---------|
|
||||||
|
| **PostgreSQL** | `igny8_postgres` | 5432 (internal) | Database |
|
||||||
|
| **Redis** | `igny8_redis` | 6379 (internal) | Cache & Celery broker |
|
||||||
|
| **pgAdmin** | `igny8_pgadmin` | 5050:80 | Database administration |
|
||||||
|
| **FileBrowser** | `igny8_filebrowser` | 8080:80 | File management |
|
||||||
|
| **Caddy** | `igny8_caddy` | 80:80, 443:443 | Reverse proxy & HTTPS |
|
||||||
|
| **Setup Helper** | `setup-helper` | - | Utility container |
|
||||||
|
|
||||||
|
### Application Stack Services
|
||||||
|
|
||||||
|
| Service | Container Name | Port | Purpose |
|
||||||
|
|---------|----------------|------|---------|
|
||||||
|
| **Backend** | `igny8_backend` | 8011:8010 | Django REST API |
|
||||||
|
| **Frontend** | `igny8_frontend` | 8021:5173 | React application |
|
||||||
|
| **Celery Worker** | `igny8_celery_worker` | - | Async task processing |
|
||||||
|
| **Celery Beat** | `igny8_celery_beat` | - | Scheduled tasks |
|
||||||
|
|
||||||
|
### Network Configuration
|
||||||
|
|
||||||
|
- **Network Name**: `igny8_net`
|
||||||
|
- **Type**: External bridge network
|
||||||
|
- **Purpose**: Inter-container communication
|
||||||
|
- **Creation**: Must be created manually before starting stacks
|
||||||
|
|
||||||
|
### Volume Management
|
||||||
|
|
||||||
|
**Infrastructure Volumes**:
|
||||||
|
- `pgdata`: PostgreSQL database data
|
||||||
|
- `redisdata`: Redis data
|
||||||
|
- `pgadmin_data`: pgAdmin configuration
|
||||||
|
- `filebrowser_db`: FileBrowser database
|
||||||
|
- `caddy_data`: Caddy SSL certificates
|
||||||
|
- `caddy_config`: Caddy configuration
|
||||||
|
|
||||||
|
**Application Volumes**:
|
||||||
|
- Host mounts for application code
|
||||||
|
- Host mounts for logs
|
||||||
|
- Docker socket for container management
|
||||||
|
|
||||||
|
### Port Allocation
|
||||||
|
|
||||||
|
| Service | External Port | Internal Port | Access |
|
||||||
|
|---------|---------------|---------------|--------|
|
||||||
|
| **pgAdmin** | 5050 | 80 | http://localhost:5050 |
|
||||||
|
| **FileBrowser** | 8080 | 80 | http://localhost:8080 |
|
||||||
|
| **Caddy** | 80, 443 | 80, 443 | https://domain.com |
|
||||||
|
| **Backend** | 8011 | 8010 | http://localhost:8011 |
|
||||||
|
| **Frontend** | 8021 | 5173 | http://localhost:8021 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## External Service Integrations
|
||||||
|
|
||||||
|
### OpenAI Integration
|
||||||
|
|
||||||
|
**Purpose**: Text generation and image generation
|
||||||
|
|
||||||
|
**Services Used**:
|
||||||
|
- GPT models for text generation
|
||||||
|
- DALL-E for image generation
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- API key stored per account in `IntegrationSettings`
|
||||||
|
- Model selection per account
|
||||||
|
- Cost tracking per request
|
||||||
|
|
||||||
|
### Runware Integration
|
||||||
|
|
||||||
|
**Purpose**: Alternative image generation service
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- API key stored per account
|
||||||
|
- Model selection (e.g., `runware:97@1`)
|
||||||
|
- Image type selection (realistic, artistic, cartoon)
|
||||||
|
|
||||||
|
### WordPress Integration
|
||||||
|
|
||||||
|
**Purpose**: Content publishing
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- WordPress URL per site
|
||||||
|
- Username and password stored per site
|
||||||
|
- REST API integration for publishing
|
||||||
|
|
||||||
|
**Workflow**:
|
||||||
|
1. Content generated in IGNY8
|
||||||
|
2. Images attached
|
||||||
|
3. Content published to WordPress via REST API
|
||||||
|
4. Status updated in IGNY8
|
||||||
|
|
||||||
|
### Stripe Integration (Planned)
|
||||||
|
|
||||||
|
**Purpose**: Payment processing
|
||||||
|
|
||||||
|
**Status**: Planned for future implementation
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Subscription management
|
||||||
|
- Payment processing
|
||||||
|
- Webhook integration
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Architecture
|
||||||
|
|
||||||
|
### Deployment Model
|
||||||
|
|
||||||
|
**Container-Based**: All services run in Docker containers
|
||||||
|
|
||||||
|
**Stack Separation**:
|
||||||
|
- Infrastructure stack runs independently
|
||||||
|
- Application stack depends on infrastructure stack
|
||||||
|
- Both stacks share the same Docker network
|
||||||
|
|
||||||
|
### Environment Configuration
|
||||||
|
|
||||||
|
**Backend Environment Variables**:
|
||||||
|
- Database connection (PostgreSQL)
|
||||||
|
- Redis connection
|
||||||
|
- Django settings (DEBUG, SECRET_KEY, etc.)
|
||||||
|
- JWT settings
|
||||||
|
- Celery configuration
|
||||||
|
|
||||||
|
**Frontend Environment Variables**:
|
||||||
|
- Backend API URL
|
||||||
|
- Environment (development/production)
|
||||||
|
|
||||||
|
**Infrastructure Environment Variables**:
|
||||||
|
- PostgreSQL credentials
|
||||||
|
- pgAdmin credentials
|
||||||
|
- FileBrowser configuration
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
**Backend Health Check**:
|
||||||
|
- Endpoint: `/api/v1/system/status/`
|
||||||
|
- Interval: 30 seconds
|
||||||
|
- Timeout: 10 seconds
|
||||||
|
- Retries: 3
|
||||||
|
|
||||||
|
**PostgreSQL Health Check**:
|
||||||
|
- Command: `pg_isready`
|
||||||
|
- Interval: 20 seconds
|
||||||
|
- Timeout: 3 seconds
|
||||||
|
- Retries: 5
|
||||||
|
|
||||||
|
**Redis Health Check**:
|
||||||
|
- Command: `redis-cli ping`
|
||||||
|
- Interval: 20 seconds
|
||||||
|
- Timeout: 3 seconds
|
||||||
|
- Retries: 5
|
||||||
|
|
||||||
|
### Scaling Considerations
|
||||||
|
|
||||||
|
**Horizontal Scaling**:
|
||||||
|
- Multiple Celery workers can be added
|
||||||
|
- Multiple backend instances can be added (with load balancer)
|
||||||
|
- Frontend can be scaled independently
|
||||||
|
|
||||||
|
**Vertical Scaling**:
|
||||||
|
- Database can be scaled with more resources
|
||||||
|
- Redis can be scaled with more memory
|
||||||
|
- Containers can be allocated more CPU/memory
|
||||||
|
|
||||||
|
### Backup & Recovery
|
||||||
|
|
||||||
|
**Database Backups**:
|
||||||
|
- PostgreSQL dumps stored in `/data/backups`
|
||||||
|
- Automated backup scripts
|
||||||
|
- Point-in-time recovery support
|
||||||
|
|
||||||
|
**Volume Backups**:
|
||||||
|
- Docker volume backups
|
||||||
|
- Application code backups
|
||||||
|
- Configuration backups
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The IGNY8 platform is built on a modern, scalable architecture using:
|
||||||
|
|
||||||
|
- **Django 5.2+** for the backend API
|
||||||
|
- **React 19** for the frontend
|
||||||
|
- **PostgreSQL 15** for data storage
|
||||||
|
- **Celery & Redis** for async processing
|
||||||
|
- **Docker** for containerization
|
||||||
|
- **Caddy** for reverse proxy and HTTPS
|
||||||
|
|
||||||
|
The architecture follows principles of:
|
||||||
|
- Configuration-driven development
|
||||||
|
- Multi-tenancy with account isolation
|
||||||
|
- Module-based organization
|
||||||
|
- Unified AI processing
|
||||||
|
- Template-based UI rendering
|
||||||
|
|
||||||
|
This architecture supports scalability, maintainability, and rapid feature development while ensuring data security and isolation.
|
||||||
|
|
||||||
795
docs/02-APP-ARCHITECTURE.md
Normal file
795
docs/02-APP-ARCHITECTURE.md
Normal file
@@ -0,0 +1,795 @@
|
|||||||
|
# IGNY8 Application Architecture
|
||||||
|
|
||||||
|
**Last Updated:** 2025-01-XX
|
||||||
|
**Purpose:** Complete application architecture documentation covering system hierarchy, modules, workflows, features, and data flow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [System Overview](#system-overview)
|
||||||
|
2. [System Hierarchy](#system-hierarchy)
|
||||||
|
3. [User Roles & Access Control](#user-roles--access-control)
|
||||||
|
4. [Module Organization](#module-organization)
|
||||||
|
5. [Complete Workflows](#complete-workflows)
|
||||||
|
6. [Data Models & Relationships](#data-models--relationships)
|
||||||
|
7. [Multi-Tenancy Architecture](#multi-tenancy-architecture)
|
||||||
|
8. [API Architecture](#api-architecture)
|
||||||
|
9. [Security Architecture](#security-architecture)
|
||||||
|
10. [Integration Points](#integration-points)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Overview
|
||||||
|
|
||||||
|
**IGNY8** is a full-stack SaaS platform for SEO keyword management and AI-driven content generation. The system provides a scalable, multi-account platform that enables users to manage keywords, generate content ideas, create AI-powered content, and publish to WordPress.
|
||||||
|
|
||||||
|
### Platform Capabilities
|
||||||
|
|
||||||
|
| Capability | Description | Module |
|
||||||
|
|------------|-------------|--------|
|
||||||
|
| **Keyword Management** | Import, organize, filter, and manage SEO keywords | Planner |
|
||||||
|
| **Keyword Clustering** | AI-powered semantic clustering of related keywords | Planner |
|
||||||
|
| **Content Ideas** | Generate content ideas from keyword clusters | Planner |
|
||||||
|
| **Content Generation** | AI-powered blog post and article generation | Writer |
|
||||||
|
| **Image Generation** | AI-powered image generation (DALL-E, Runware) | Writer |
|
||||||
|
| **WordPress Integration** | Direct publishing to WordPress sites | Writer |
|
||||||
|
| **Account Management** | Multi-account SaaS with user roles | Auth |
|
||||||
|
| **Billing & Credits** | Credit-based billing system | Billing |
|
||||||
|
| **AI Configuration** | Customizable AI prompts and settings | System |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Hierarchy
|
||||||
|
|
||||||
|
### Entity Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
Account (1) ──< (N) User
|
||||||
|
Account (1) ──< (1) Subscription ──> (1) Plan
|
||||||
|
Account (1) ──< (N) Site
|
||||||
|
Site (1) ──< (1-5) Sector
|
||||||
|
Sector (1) ──< (N) Keywords, Clusters, ContentIdeas, Tasks
|
||||||
|
Cluster (1) ──< (N) Keywords (Many-to-Many)
|
||||||
|
Cluster (1) ──< (N) ContentIdeas
|
||||||
|
ContentIdeas (1) ──< (N) Tasks
|
||||||
|
Task (1) ──> (1) Content
|
||||||
|
Task (1) ──< (N) Images
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hierarchy Details
|
||||||
|
|
||||||
|
**Account Level**:
|
||||||
|
- Top-level organization/workspace
|
||||||
|
- Contains users, sites, subscriptions, and all data
|
||||||
|
- Has credit balance and plan assignment
|
||||||
|
- Status: active, suspended, trial, cancelled
|
||||||
|
|
||||||
|
**User Level**:
|
||||||
|
- Individual user accounts within an account
|
||||||
|
- Has role (developer, owner, admin, editor, viewer)
|
||||||
|
- Can belong to only one account
|
||||||
|
- Access controlled by role and site permissions
|
||||||
|
|
||||||
|
**Site Level**:
|
||||||
|
- Workspace within an account (1-N relationship)
|
||||||
|
- Can have multiple active sites simultaneously
|
||||||
|
- Has WordPress integration settings (URL, username, password)
|
||||||
|
- Can be associated with an industry
|
||||||
|
- Status: active, inactive, suspended
|
||||||
|
|
||||||
|
**Sector Level**:
|
||||||
|
- Content category within a site (1-5 per site)
|
||||||
|
- Organizes keywords, clusters, ideas, and tasks
|
||||||
|
- Can reference an industry sector template
|
||||||
|
- Status: active, inactive
|
||||||
|
|
||||||
|
**Content Level**:
|
||||||
|
- Keywords, Clusters, ContentIdeas belong to Sector
|
||||||
|
- Tasks, Content, Images belong to Sector
|
||||||
|
- All content is automatically associated with Account and Site
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## User Roles & Access Control
|
||||||
|
|
||||||
|
### User Roles
|
||||||
|
|
||||||
|
| Role | Access Level | Description | Permissions |
|
||||||
|
|------|--------------|-------------|-------------|
|
||||||
|
| **Developer** | System-wide | Full system access, bypasses all restrictions | All accounts, all sites, all data, system settings |
|
||||||
|
| **Owner** | Account-wide | Full account access, can manage users and billing | All sites in account, user management, billing |
|
||||||
|
| **Admin** | Account-wide | Account admin access, can manage content and users | All sites in account, content management, user management |
|
||||||
|
| **Editor** | Site-specific | Content editing access, can manage clusters/tasks | Granted sites only, content editing |
|
||||||
|
| **Viewer** | Site-specific | Read-only access | Granted sites only, read-only |
|
||||||
|
| **System Bot** | System-wide | System automation user | All accounts, all sites, all data |
|
||||||
|
|
||||||
|
### Access Control Matrix
|
||||||
|
|
||||||
|
| User Role | Account Access | Site Access | Data Access | User Management | Billing |
|
||||||
|
|-----------|----------------|-------------|-------------|------------------|---------|
|
||||||
|
| Developer | All accounts | All sites | All data | Yes | Yes |
|
||||||
|
| System Bot | All accounts | All sites | All data | No | No |
|
||||||
|
| Owner | Own account | All sites in account | All data in account | Yes | Yes |
|
||||||
|
| Admin | Own account | All sites in account | All data in account | Yes | No |
|
||||||
|
| Editor | Own account | Granted sites only | Data in granted sites | No | No |
|
||||||
|
| Viewer | Own account | Granted sites only | Read-only in granted sites | No | No |
|
||||||
|
|
||||||
|
### Site Access Control
|
||||||
|
|
||||||
|
**Automatic Access**:
|
||||||
|
- Owners and Admins: Automatic access to all sites in their account
|
||||||
|
- Developers and System Bot: Access to all sites across all accounts
|
||||||
|
|
||||||
|
**Explicit Access**:
|
||||||
|
- Editors and Viewers: Require explicit `SiteUserAccess` records
|
||||||
|
- Access granted by Owner or Admin
|
||||||
|
- Access can be revoked at any time
|
||||||
|
|
||||||
|
### Account Isolation
|
||||||
|
|
||||||
|
**Principle**: All data is automatically filtered by account.
|
||||||
|
|
||||||
|
**Implementation**:
|
||||||
|
- All models inherit `AccountBaseModel` with `account` ForeignKey
|
||||||
|
- All ViewSets inherit `AccountModelViewSet` with automatic filtering
|
||||||
|
- Middleware sets `request.account` from JWT token
|
||||||
|
- Queries automatically filter by account (except for Developer/System Bot)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Module Organization
|
||||||
|
|
||||||
|
### Module Structure
|
||||||
|
|
||||||
|
| Module | Purpose | Models | ViewSets | Celery Tasks |
|
||||||
|
|--------|---------|--------|----------|--------------|
|
||||||
|
| **Planner** | Keyword management & content planning | Keywords, Clusters, ContentIdeas | KeywordViewSet, ClusterViewSet, ContentIdeasViewSet | auto_cluster_keywords_task, auto_generate_ideas_task |
|
||||||
|
| **Writer** | Content generation & management | Tasks, Content, Images | TasksViewSet, ImagesViewSet | auto_generate_content_task, auto_generate_images_task |
|
||||||
|
| **System** | Settings, prompts, integrations | AIPrompt, IntegrationSettings, AuthorProfile, Strategy | AIPromptViewSet, IntegrationSettingsViewSet, AuthorProfileViewSet | - |
|
||||||
|
| **Billing** | Credits, transactions, usage | CreditTransaction, CreditUsageLog | CreditTransactionViewSet, CreditUsageLogViewSet | - |
|
||||||
|
| **Auth** | Multi-tenancy, users, accounts | Account, User, Plan, Site, Sector | AccountViewSet, UserViewSet, SiteViewSet, SectorViewSet | - |
|
||||||
|
|
||||||
|
### Module Dependencies
|
||||||
|
|
||||||
|
```
|
||||||
|
Auth (Core)
|
||||||
|
├── Planner (depends on Auth)
|
||||||
|
├── Writer (depends on Auth, Planner)
|
||||||
|
├── System (depends on Auth)
|
||||||
|
└── Billing (depends on Auth)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module Features
|
||||||
|
|
||||||
|
#### Planner Module
|
||||||
|
|
||||||
|
**Purpose**: Keyword research, clustering, and content idea generation
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Keyword import (CSV/manual)
|
||||||
|
- Keyword filtering and organization
|
||||||
|
- AI-powered keyword clustering
|
||||||
|
- Content idea generation from clusters
|
||||||
|
- Keyword-to-cluster mapping
|
||||||
|
- Cluster metrics and analytics
|
||||||
|
|
||||||
|
**Models**:
|
||||||
|
- `Keywords`: Individual keywords with metrics (volume, difficulty, intent)
|
||||||
|
- `Clusters`: Groups of related keywords
|
||||||
|
- `ContentIdeas`: Content ideas generated from clusters
|
||||||
|
|
||||||
|
#### Writer Module
|
||||||
|
|
||||||
|
**Purpose**: Content generation, image generation, and publishing
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Task creation from content ideas
|
||||||
|
- AI-powered content generation
|
||||||
|
- Content editing and review
|
||||||
|
- Image prompt extraction
|
||||||
|
- AI-powered image generation
|
||||||
|
- WordPress publishing
|
||||||
|
|
||||||
|
**Models**:
|
||||||
|
- `Tasks`: Content generation tasks
|
||||||
|
- `Content`: Generated HTML content
|
||||||
|
- `Images`: Generated images (featured, in-article)
|
||||||
|
|
||||||
|
#### System Module
|
||||||
|
|
||||||
|
**Purpose**: System configuration and AI settings
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- AI prompt management
|
||||||
|
- Integration settings (OpenAI, Runware)
|
||||||
|
- Author profile management
|
||||||
|
- Content strategy management
|
||||||
|
- System status and monitoring
|
||||||
|
|
||||||
|
**Models**:
|
||||||
|
- `AIPrompt`: AI prompt templates
|
||||||
|
- `IntegrationSettings`: API keys and configuration
|
||||||
|
- `AuthorProfile`: Writing style profiles
|
||||||
|
- `Strategy`: Content strategies
|
||||||
|
|
||||||
|
#### Billing Module
|
||||||
|
|
||||||
|
**Purpose**: Credit management and usage tracking
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Credit balance tracking
|
||||||
|
- Credit transactions
|
||||||
|
- Usage logging
|
||||||
|
- Cost tracking
|
||||||
|
|
||||||
|
**Models**:
|
||||||
|
- `CreditTransaction`: Credit additions and deductions
|
||||||
|
- `CreditUsageLog`: Usage tracking with cost
|
||||||
|
|
||||||
|
#### Auth Module
|
||||||
|
|
||||||
|
**Purpose**: Multi-tenancy and user management
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Account management
|
||||||
|
- User management
|
||||||
|
- Plan management
|
||||||
|
- Site and sector management
|
||||||
|
- Industry templates
|
||||||
|
|
||||||
|
**Models**:
|
||||||
|
- `Account`: Top-level organization
|
||||||
|
- `User`: User accounts
|
||||||
|
- `Plan`: Subscription plans
|
||||||
|
- `Site`: Sites within accounts
|
||||||
|
- `Sector`: Sectors within sites
|
||||||
|
- `Industry`: Global industry templates
|
||||||
|
- `IndustrySector`: Industry sector templates
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Complete Workflows
|
||||||
|
|
||||||
|
### 1. Account Setup Workflow
|
||||||
|
|
||||||
|
**Purpose**: Onboard a new account and user
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User signs up via `/signup`
|
||||||
|
2. Account created with default plan
|
||||||
|
3. Owner user created and linked to account
|
||||||
|
4. User signs in via `/signin`
|
||||||
|
5. JWT token generated and returned
|
||||||
|
6. Frontend stores token and redirects to dashboard
|
||||||
|
7. User creates first site (optional)
|
||||||
|
8. User creates sectors (1-5 per site, optional)
|
||||||
|
9. User configures integration settings (OpenAI, Runware)
|
||||||
|
10. System ready for use
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- 1 Account record
|
||||||
|
- 1 User record (owner role)
|
||||||
|
- 1 Subscription record (default plan)
|
||||||
|
- 0-N Site records
|
||||||
|
- 0-N Sector records (per site)
|
||||||
|
- 1 IntegrationSettings record (per integration type)
|
||||||
|
|
||||||
|
### 2. Keyword Management Workflow
|
||||||
|
|
||||||
|
**Purpose**: Import, organize, and cluster keywords
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/planner/keywords`
|
||||||
|
2. User imports keywords via CSV or manual entry
|
||||||
|
3. Keywords validated and stored in database
|
||||||
|
4. Keywords displayed in table with filters
|
||||||
|
5. User filters keywords by sector, status, intent, etc.
|
||||||
|
6. User selects keywords for clustering
|
||||||
|
7. User clicks "Auto Cluster" action
|
||||||
|
8. Backend validates keyword IDs
|
||||||
|
9. Celery task queued (`auto_cluster_keywords_task`)
|
||||||
|
10. Task ID returned to frontend
|
||||||
|
11. Frontend polls progress endpoint
|
||||||
|
12. Celery worker processes task:
|
||||||
|
- Loads keywords from database
|
||||||
|
- Builds AI prompt with keyword data
|
||||||
|
- Calls OpenAI API for clustering
|
||||||
|
- Parses cluster response
|
||||||
|
- Creates Cluster records
|
||||||
|
- Links keywords to clusters
|
||||||
|
13. Progress updates sent to frontend
|
||||||
|
14. Task completes
|
||||||
|
15. Frontend displays new clusters
|
||||||
|
16. User can view clusters, edit cluster names, add/remove keywords
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- N Keyword records (if imported)
|
||||||
|
- M Cluster records (created by AI)
|
||||||
|
- N-M Keyword-to-Cluster relationships
|
||||||
|
|
||||||
|
**AI Function**: Auto Cluster Keywords
|
||||||
|
|
||||||
|
### 3. Content Idea Generation Workflow
|
||||||
|
|
||||||
|
**Purpose**: Generate content ideas from keyword clusters
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/planner/clusters`
|
||||||
|
2. User selects one or more clusters
|
||||||
|
3. User clicks "Generate Ideas" action
|
||||||
|
4. Backend validates cluster IDs
|
||||||
|
5. Celery task queued (`auto_generate_ideas_task`)
|
||||||
|
6. Task ID returned to frontend
|
||||||
|
7. Frontend polls progress endpoint
|
||||||
|
8. Celery worker processes task:
|
||||||
|
- Loads clusters and keywords
|
||||||
|
- Builds AI prompt with cluster data
|
||||||
|
- Calls OpenAI API for idea generation
|
||||||
|
- Parses idea response
|
||||||
|
- Creates ContentIdeas records
|
||||||
|
- Links ideas to clusters
|
||||||
|
9. Progress updates sent to frontend
|
||||||
|
10. Task completes
|
||||||
|
11. Frontend displays new content ideas
|
||||||
|
12. User can view ideas, edit titles, prioritize ideas
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- N ContentIdeas records (created by AI)
|
||||||
|
- N ContentIdeas-to-Cluster relationships
|
||||||
|
|
||||||
|
**AI Function**: Generate Ideas
|
||||||
|
|
||||||
|
### 4. Content Generation Workflow
|
||||||
|
|
||||||
|
**Purpose**: Generate AI-powered content from content ideas
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/planner/ideas`
|
||||||
|
2. User selects one or more content ideas
|
||||||
|
3. User clicks "Create Tasks" action
|
||||||
|
4. Task records created for each idea
|
||||||
|
5. User navigates to `/writer/tasks`
|
||||||
|
6. User selects tasks for content generation
|
||||||
|
7. User clicks "Generate Content" action
|
||||||
|
8. Backend validates task IDs
|
||||||
|
9. Celery task queued (`auto_generate_content_task`)
|
||||||
|
10. Task ID returned to frontend
|
||||||
|
11. Frontend polls progress endpoint
|
||||||
|
12. Celery worker processes task:
|
||||||
|
- Loads tasks and related data (cluster, keywords, idea)
|
||||||
|
- Builds AI prompt with task data
|
||||||
|
- Calls OpenAI API for content generation
|
||||||
|
- Parses HTML content response
|
||||||
|
- Creates/updates Content records
|
||||||
|
- Updates task status
|
||||||
|
13. Progress updates sent to frontend
|
||||||
|
14. Task completes
|
||||||
|
15. Frontend displays generated content
|
||||||
|
16. User can review and edit content
|
||||||
|
17. User navigates to `/writer/content` to view content
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- N Task records (from ideas)
|
||||||
|
- N Content records (generated HTML)
|
||||||
|
|
||||||
|
**AI Function**: Generate Content
|
||||||
|
|
||||||
|
### 5. Image Generation Workflow
|
||||||
|
|
||||||
|
**Purpose**: Generate images for content
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/writer/content`
|
||||||
|
2. User selects content items
|
||||||
|
3. User clicks "Generate Image Prompts" action (optional, can skip)
|
||||||
|
4. Backend validates content IDs
|
||||||
|
5. Celery task queued (`auto_generate_image_prompts_task`)
|
||||||
|
6. Task processes:
|
||||||
|
- Loads content HTML
|
||||||
|
- Builds AI prompt for prompt extraction
|
||||||
|
- Calls OpenAI API
|
||||||
|
- Parses image prompts (featured, in-article)
|
||||||
|
- Creates/updates Images records with prompts
|
||||||
|
7. User clicks "Generate Images" action
|
||||||
|
8. Backend validates image IDs
|
||||||
|
9. Celery task queued (`auto_generate_images_task`)
|
||||||
|
10. Task processes:
|
||||||
|
- Loads images with prompts
|
||||||
|
- Builds image generation prompt
|
||||||
|
- Calls OpenAI DALL-E or Runware API
|
||||||
|
- Receives image URLs
|
||||||
|
- Updates Images records with URLs
|
||||||
|
11. Images displayed in frontend
|
||||||
|
12. User can view images, regenerate, or delete
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- N Images records (with prompts)
|
||||||
|
- N Images records (with image URLs)
|
||||||
|
|
||||||
|
**AI Functions**: Generate Image Prompts, Generate Images
|
||||||
|
|
||||||
|
### 6. WordPress Publishing Workflow
|
||||||
|
|
||||||
|
**Purpose**: Publish content to WordPress
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/writer/content`
|
||||||
|
2. User selects content to publish
|
||||||
|
3. User clicks "Publish to WordPress" action
|
||||||
|
4. Backend validates:
|
||||||
|
- Site has WordPress URL configured
|
||||||
|
- Site has WordPress credentials
|
||||||
|
- Content is ready (status: review or draft)
|
||||||
|
5. Backend calls WordPress REST API:
|
||||||
|
- Creates post with content HTML
|
||||||
|
- Uploads featured image (if available)
|
||||||
|
- Uploads in-article images (if available)
|
||||||
|
- Sets post status (draft, publish)
|
||||||
|
6. WordPress post ID stored in Content record
|
||||||
|
7. Content status updated to "published"
|
||||||
|
8. Frontend displays success message
|
||||||
|
9. User can view published content in WordPress
|
||||||
|
|
||||||
|
**Data Updated**:
|
||||||
|
- Content record: `wp_post_id`, `status` = "published"
|
||||||
|
|
||||||
|
**Integration**: WordPress REST API
|
||||||
|
|
||||||
|
### 7. User Management Workflow
|
||||||
|
|
||||||
|
**Purpose**: Add users to account and manage permissions
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. Owner/Admin navigates to `/settings/users`
|
||||||
|
2. User clicks "Add User" action
|
||||||
|
3. User enters email and selects role
|
||||||
|
4. Backend creates User record:
|
||||||
|
- Email validated (unique per account)
|
||||||
|
- Role assigned
|
||||||
|
- Account linked
|
||||||
|
- Password set (or invitation sent)
|
||||||
|
5. If role is Editor/Viewer:
|
||||||
|
- Owner/Admin grants site access
|
||||||
|
- SiteUserAccess records created
|
||||||
|
6. New user receives invitation email
|
||||||
|
7. New user signs in and accesses granted sites
|
||||||
|
|
||||||
|
**Data Created**:
|
||||||
|
- 1 User record
|
||||||
|
- 0-N SiteUserAccess records (for Editor/Viewer roles)
|
||||||
|
|
||||||
|
### 8. Integration Configuration Workflow
|
||||||
|
|
||||||
|
**Purpose**: Configure AI service integrations
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
1. User navigates to `/settings/integration`
|
||||||
|
2. User selects integration type (OpenAI, Runware)
|
||||||
|
3. User enters API key
|
||||||
|
4. User clicks "Test Connection" (optional)
|
||||||
|
5. Backend validates API key:
|
||||||
|
- Makes test API call
|
||||||
|
- Returns connection status
|
||||||
|
6. User saves integration settings
|
||||||
|
7. Backend stores API key in IntegrationSettings
|
||||||
|
8. Integration ready for use in AI functions
|
||||||
|
|
||||||
|
**Data Created/Updated**:
|
||||||
|
- 1 IntegrationSettings record (per integration type)
|
||||||
|
|
||||||
|
**Test Functions**: Test OpenAI, Test Runware
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Models & Relationships
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
**Account Model**:
|
||||||
|
- Fields: name, slug, owner, plan, credits, status
|
||||||
|
- Relationships: Users (1-N), Sites (1-N), Subscription (1-1)
|
||||||
|
|
||||||
|
**User Model**:
|
||||||
|
- Fields: email, account, role
|
||||||
|
- Relationships: Account (N-1), SiteUserAccess (N-M via SiteUserAccess)
|
||||||
|
|
||||||
|
**Plan Model**:
|
||||||
|
- Fields: name, price, limits (users, sites, keywords, clusters, etc.), credits
|
||||||
|
- Relationships: Accounts (1-N via Subscription)
|
||||||
|
|
||||||
|
**Site Model**:
|
||||||
|
- Fields: name, slug, domain, industry, status, wp_url, wp_username, wp_app_password
|
||||||
|
- Relationships: Account (N-1), Sectors (1-N), Industry (N-1)
|
||||||
|
|
||||||
|
**Sector Model**:
|
||||||
|
- Fields: name, slug, site, industry_sector, status
|
||||||
|
- Relationships: Site (N-1), IndustrySector (N-1), Keywords/Clusters/Ideas/Tasks (1-N)
|
||||||
|
|
||||||
|
### Planner Models
|
||||||
|
|
||||||
|
**Keywords Model**:
|
||||||
|
- Fields: keyword, volume, difficulty, intent, cluster (M-N)
|
||||||
|
- Relationships: Sector (N-1), Clusters (M-N)
|
||||||
|
|
||||||
|
**Clusters Model**:
|
||||||
|
- Fields: name, description, keywords_count, volume
|
||||||
|
- Relationships: Sector (N-1), Keywords (M-N), ContentIdeas (1-N)
|
||||||
|
|
||||||
|
**ContentIdeas Model**:
|
||||||
|
- Fields: idea_title, description, cluster, status
|
||||||
|
- Relationships: Sector (N-1), Cluster (N-1), Tasks (1-N)
|
||||||
|
|
||||||
|
### Writer Models
|
||||||
|
|
||||||
|
**Tasks Model**:
|
||||||
|
- Fields: title, description, cluster, idea, status, content
|
||||||
|
- Relationships: Sector (N-1), Cluster (N-1), ContentIdeas (N-1), Content (1-1), Images (1-N)
|
||||||
|
|
||||||
|
**Content Model**:
|
||||||
|
- Fields: task, html_content, word_count, status, wp_post_id
|
||||||
|
- Relationships: Task (1-1), Images (1-N)
|
||||||
|
|
||||||
|
**Images Model**:
|
||||||
|
- Fields: task, content, image_type, prompt, image_url, status
|
||||||
|
- Relationships: Task (N-1), Content (N-1)
|
||||||
|
|
||||||
|
### System Models
|
||||||
|
|
||||||
|
**AIPrompt Model**:
|
||||||
|
- Fields: prompt_type, prompt_value, account
|
||||||
|
- Relationships: Account (N-1)
|
||||||
|
|
||||||
|
**IntegrationSettings Model**:
|
||||||
|
- Fields: integration_type, config (JSON), account
|
||||||
|
- Relationships: Account (N-1)
|
||||||
|
|
||||||
|
**AuthorProfile Model**:
|
||||||
|
- Fields: name, description, tone, language, account
|
||||||
|
- Relationships: Account (N-1)
|
||||||
|
|
||||||
|
**Strategy Model**:
|
||||||
|
- Fields: name, description, sector, prompt_types, account
|
||||||
|
- Relationships: Account (N-1), Sector (N-1)
|
||||||
|
|
||||||
|
### Billing Models
|
||||||
|
|
||||||
|
**CreditTransaction Model**:
|
||||||
|
- Fields: account, transaction_type, amount, balance_after
|
||||||
|
- Relationships: Account (N-1)
|
||||||
|
|
||||||
|
**CreditUsageLog Model**:
|
||||||
|
- Fields: account, operation_type, credits_used, cost_usd
|
||||||
|
- Relationships: Account (N-1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multi-Tenancy Architecture
|
||||||
|
|
||||||
|
### Account Isolation
|
||||||
|
|
||||||
|
**Implementation Levels**:
|
||||||
|
1. **Model Level**: All models inherit `AccountBaseModel` with `account` ForeignKey
|
||||||
|
2. **ViewSet Level**: All ViewSets inherit `AccountModelViewSet` with automatic filtering
|
||||||
|
3. **Middleware Level**: `AccountContextMiddleware` sets `request.account` from JWT
|
||||||
|
|
||||||
|
**Filtering**:
|
||||||
|
- All queries automatically filter by `account = request.account`
|
||||||
|
- Developer and System Bot users bypass account filtering
|
||||||
|
- System accounts bypass account filtering
|
||||||
|
|
||||||
|
### Site/Sector Hierarchy
|
||||||
|
|
||||||
|
**Purpose**: Organize content within accounts
|
||||||
|
|
||||||
|
**Structure**:
|
||||||
|
```
|
||||||
|
Account
|
||||||
|
└── Site 1 (Active)
|
||||||
|
├── Sector 1 (Active)
|
||||||
|
│ ├── Keywords
|
||||||
|
│ ├── Clusters
|
||||||
|
│ ├── ContentIdeas
|
||||||
|
│ └── Tasks
|
||||||
|
├── Sector 2 (Active)
|
||||||
|
└── Sector 3 (Inactive)
|
||||||
|
└── Site 2 (Active)
|
||||||
|
└── Sector 1 (Active)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Constraints**:
|
||||||
|
- Maximum 5 active sectors per site
|
||||||
|
- Multiple sites can be active simultaneously
|
||||||
|
- All content must belong to a site and sector
|
||||||
|
|
||||||
|
### Data Isolation Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Request with JWT Token
|
||||||
|
↓
|
||||||
|
AccountContextMiddleware
|
||||||
|
├── Extract Account ID from JWT
|
||||||
|
├── Load Account Object
|
||||||
|
└── Set request.account
|
||||||
|
↓
|
||||||
|
ViewSet.get_queryset()
|
||||||
|
├── Check User Role
|
||||||
|
├── Filter by Account (if not admin/developer)
|
||||||
|
└── Filter by Accessible Sites (if not owner/admin)
|
||||||
|
↓
|
||||||
|
Database Query
|
||||||
|
↓
|
||||||
|
Results (Account-Isolated)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Architecture
|
||||||
|
|
||||||
|
### API Structure
|
||||||
|
|
||||||
|
**Base URL**: `/api/v1/`
|
||||||
|
|
||||||
|
**Module Endpoints**:
|
||||||
|
- `/api/v1/auth/` - Accounts, users, sites, sectors, plans
|
||||||
|
- `/api/v1/planner/` - Keywords, clusters, ideas
|
||||||
|
- `/api/v1/writer/` - Tasks, content, images
|
||||||
|
- `/api/v1/system/` - Prompts, integrations, author-profiles, strategies
|
||||||
|
- `/api/v1/billing/` - Credits, transactions, usage
|
||||||
|
|
||||||
|
### Authentication Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. User Signs In
|
||||||
|
↓
|
||||||
|
2. Backend Validates Credentials
|
||||||
|
↓
|
||||||
|
3. JWT Token Generated
|
||||||
|
↓
|
||||||
|
4. Token Returned to Frontend
|
||||||
|
↓
|
||||||
|
5. Frontend Stores Token (localStorage)
|
||||||
|
↓
|
||||||
|
6. Frontend Includes Token in Requests (Authorization: Bearer {token})
|
||||||
|
↓
|
||||||
|
7. Backend Validates Token
|
||||||
|
↓
|
||||||
|
8. Account Context Set
|
||||||
|
↓
|
||||||
|
9. Request Processed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Format
|
||||||
|
|
||||||
|
**Success Response**:
|
||||||
|
- `success`: true
|
||||||
|
- `data`: Response data
|
||||||
|
- `message`: Optional message
|
||||||
|
|
||||||
|
**Error Response**:
|
||||||
|
- `success`: false
|
||||||
|
- `message`: Error message
|
||||||
|
- `errors`: Validation errors (if applicable)
|
||||||
|
|
||||||
|
**Pagination Response**:
|
||||||
|
- `count`: Total count
|
||||||
|
- `next`: Next page URL
|
||||||
|
- `previous`: Previous page URL
|
||||||
|
- `results`: Array of results
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Architecture
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
**Methods**:
|
||||||
|
- JWT (JSON Web Tokens) - Primary method
|
||||||
|
- Session-based auth - Fallback for admin
|
||||||
|
|
||||||
|
**Token Management**:
|
||||||
|
- Tokens stored in localStorage
|
||||||
|
- Tokens included in `Authorization: Bearer {token}` header
|
||||||
|
- Token refresh mechanism (future implementation)
|
||||||
|
|
||||||
|
### Authorization
|
||||||
|
|
||||||
|
**Role-Based Access Control (RBAC)**:
|
||||||
|
- Role checked on every request
|
||||||
|
- Permissions enforced at ViewSet level
|
||||||
|
- Action-level permissions for sensitive operations
|
||||||
|
|
||||||
|
**Data Access Control**:
|
||||||
|
- Account-level: Automatic filtering by account
|
||||||
|
- Site-level: Filtering by accessible sites
|
||||||
|
- Action-level: Permission checks in ViewSet actions
|
||||||
|
|
||||||
|
### Data Security
|
||||||
|
|
||||||
|
**Account Isolation**:
|
||||||
|
- All queries filtered by account
|
||||||
|
- Admin/Developer override for system accounts
|
||||||
|
- No cross-account data leakage
|
||||||
|
|
||||||
|
**Site Access Control**:
|
||||||
|
- Users can only access granted sites
|
||||||
|
- Admin/Developer override for all sites
|
||||||
|
- Explicit access grants for Editor/Viewer roles
|
||||||
|
|
||||||
|
**API Security**:
|
||||||
|
- CORS configured for frontend domain
|
||||||
|
- CSRF enabled for session-based auth
|
||||||
|
- Input validation via DRF serializers
|
||||||
|
- Rate limiting (future implementation)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Integration Points
|
||||||
|
|
||||||
|
### OpenAI Integration
|
||||||
|
|
||||||
|
**Purpose**: Text generation and image generation
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- API key stored per account in `IntegrationSettings`
|
||||||
|
- Model selection per account
|
||||||
|
- Cost tracking per request
|
||||||
|
|
||||||
|
**Services Used**:
|
||||||
|
- GPT models for text generation
|
||||||
|
- DALL-E for image generation
|
||||||
|
|
||||||
|
### Runware Integration
|
||||||
|
|
||||||
|
**Purpose**: Alternative image generation service
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- API key stored per account
|
||||||
|
- Model selection (e.g., `runware:97@1`)
|
||||||
|
- Image type selection (realistic, artistic, cartoon)
|
||||||
|
|
||||||
|
### WordPress Integration
|
||||||
|
|
||||||
|
**Purpose**: Content publishing
|
||||||
|
|
||||||
|
**Configuration**:
|
||||||
|
- WordPress URL per site
|
||||||
|
- Username and password stored per site
|
||||||
|
- REST API integration for publishing
|
||||||
|
|
||||||
|
**Workflow**:
|
||||||
|
1. Content generated in IGNY8
|
||||||
|
2. Images attached
|
||||||
|
3. Content published to WordPress via REST API
|
||||||
|
4. Status updated in IGNY8
|
||||||
|
|
||||||
|
### Stripe Integration (Planned)
|
||||||
|
|
||||||
|
**Purpose**: Payment processing
|
||||||
|
|
||||||
|
**Status**: Planned for future implementation
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Subscription management
|
||||||
|
- Payment processing
|
||||||
|
- Webhook integration
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The IGNY8 application architecture provides:
|
||||||
|
|
||||||
|
1. **Multi-Tenancy**: Complete account isolation with automatic filtering
|
||||||
|
2. **Hierarchical Organization**: Account > Site > Sector > Content structure
|
||||||
|
3. **Role-Based Access**: Granular permissions for different user roles
|
||||||
|
4. **Module-Based Design**: Clear separation of concerns across modules
|
||||||
|
5. **Complete Workflows**: End-to-end workflows from keyword import to publishing
|
||||||
|
6. **AI Integration**: Unified AI framework for all AI operations
|
||||||
|
7. **WordPress Integration**: Direct publishing to WordPress sites
|
||||||
|
8. **Credit System**: Credit-based billing and usage tracking
|
||||||
|
9. **Security First**: JWT auth, RBAC, data isolation
|
||||||
|
10. **Scalable Design**: Supports multiple accounts, sites, and users
|
||||||
|
|
||||||
|
This architecture ensures scalability, maintainability, and extensibility while providing a robust foundation for the IGNY8 platform.
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
# IGNY8 Frontend Documentation
|
# IGNY8 Frontend Documentation
|
||||||
|
|
||||||
**Version:** 1.0
|
|
||||||
**Last Updated:** 2025-01-XX
|
**Last Updated:** 2025-01-XX
|
||||||
**Purpose:** Complete frontend documentation covering pages, components, templates, routing, state management, and configuration system.
|
**Purpose:** Complete frontend documentation covering architecture, pages, components, routing, state management, and configuration system.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -17,9 +16,8 @@
|
|||||||
7. [State Management](#state-management)
|
7. [State Management](#state-management)
|
||||||
8. [API Integration](#api-integration)
|
8. [API Integration](#api-integration)
|
||||||
9. [Configuration System](#configuration-system)
|
9. [Configuration System](#configuration-system)
|
||||||
10. [Pages](#pages)
|
10. [Pages & Features](#pages--features)
|
||||||
11. [Hooks](#hooks)
|
11. [Hooks & Utilities](#hooks--utilities)
|
||||||
12. [Utilities](#utilities)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -76,24 +74,58 @@ frontend/src/
|
|||||||
│ │ ├── Dashboard.tsx
|
│ │ ├── Dashboard.tsx
|
||||||
│ │ ├── Keywords.tsx
|
│ │ ├── Keywords.tsx
|
||||||
│ │ ├── Clusters.tsx
|
│ │ ├── Clusters.tsx
|
||||||
│ │ └── Ideas.tsx
|
│ │ ├── Ideas.tsx
|
||||||
|
│ │ ├── KeywordOpportunities.tsx
|
||||||
|
│ │ └── Mapping.tsx
|
||||||
│ ├── Writer/ # Writer module pages
|
│ ├── Writer/ # Writer module pages
|
||||||
│ │ ├── Dashboard.tsx
|
│ │ ├── Dashboard.tsx
|
||||||
│ │ ├── Tasks.tsx
|
│ │ ├── Tasks.tsx
|
||||||
│ │ ├── Content.tsx
|
│ │ ├── Content.tsx
|
||||||
|
│ │ ├── ContentView.tsx
|
||||||
│ │ ├── Drafts.tsx
|
│ │ ├── Drafts.tsx
|
||||||
│ │ ├── Images.tsx
|
│ │ ├── Images.tsx
|
||||||
│ │ └── Published.tsx
|
│ │ └── Published.tsx
|
||||||
|
│ ├── Thinker/ # Thinker module pages
|
||||||
|
│ │ ├── Dashboard.tsx
|
||||||
|
│ │ ├── Prompts.tsx
|
||||||
|
│ │ ├── AuthorProfiles.tsx
|
||||||
|
│ │ ├── Strategies.tsx
|
||||||
|
│ │ ├── Profile.tsx
|
||||||
|
│ │ └── ImageTesting.tsx
|
||||||
|
│ ├── Billing/ # Billing module pages
|
||||||
|
│ │ ├── Credits.tsx
|
||||||
|
│ │ ├── Transactions.tsx
|
||||||
|
│ │ └── Usage.tsx
|
||||||
│ ├── Settings/ # Settings pages
|
│ ├── Settings/ # Settings pages
|
||||||
│ │ ├── General.tsx
|
│ │ ├── General.tsx
|
||||||
│ │ ├── Users.tsx
|
│ │ ├── Users.tsx
|
||||||
│ │ ├── Sites.tsx
|
│ │ ├── Sites.tsx
|
||||||
│ │ ├── Integration.tsx
|
│ │ ├── Integration.tsx
|
||||||
│ │ └── ...
|
│ │ ├── AI.tsx
|
||||||
|
│ │ ├── Plans.tsx
|
||||||
|
│ │ ├── Industries.tsx
|
||||||
|
│ │ ├── Status.tsx
|
||||||
|
│ │ ├── Subscriptions.tsx
|
||||||
|
│ │ ├── Account.tsx
|
||||||
|
│ │ ├── Modules.tsx
|
||||||
|
│ │ ├── System.tsx
|
||||||
|
│ │ ├── ImportExport.tsx
|
||||||
|
│ │ └── UiElements/ # UI element examples
|
||||||
|
│ ├── Help/ # Help pages
|
||||||
|
│ │ ├── Help.tsx
|
||||||
|
│ │ ├── Docs.tsx
|
||||||
|
│ │ ├── SystemTesting.tsx
|
||||||
|
│ │ └── FunctionTesting.tsx
|
||||||
|
│ ├── Reference/ # Reference data pages
|
||||||
|
│ │ ├── Industries.tsx
|
||||||
|
│ │ └── SeedKeywords.tsx
|
||||||
│ ├── AuthPages/ # Authentication pages
|
│ ├── AuthPages/ # Authentication pages
|
||||||
│ │ ├── SignIn.tsx
|
│ │ ├── SignIn.tsx
|
||||||
│ │ └── SignUp.tsx
|
│ │ └── SignUp.tsx
|
||||||
│ └── ...
|
│ ├── Dashboard/ # Main dashboard
|
||||||
|
│ │ └── Home.tsx
|
||||||
|
│ └── OtherPage/ # Other pages
|
||||||
|
│ └── NotFound.tsx
|
||||||
├── templates/ # 4 universal templates
|
├── templates/ # 4 universal templates
|
||||||
│ ├── DashboardTemplate.tsx
|
│ ├── DashboardTemplate.tsx
|
||||||
│ ├── TablePageTemplate.tsx
|
│ ├── TablePageTemplate.tsx
|
||||||
@@ -135,8 +167,6 @@ frontend/src/
|
|||||||
├── hooks/ # Custom React hooks
|
├── hooks/ # Custom React hooks
|
||||||
│ ├── useProgressModal.ts # Progress modal for long-running tasks
|
│ ├── useProgressModal.ts # Progress modal for long-running tasks
|
||||||
│ └── useAuth.ts # Authentication hook
|
│ └── useAuth.ts # Authentication hook
|
||||||
├── layout/ # Layout components
|
|
||||||
│ └── AppLayout.tsx # Main app layout wrapper
|
|
||||||
├── utils/ # Utility functions
|
├── utils/ # Utility functions
|
||||||
│ └── difficulty.ts # Difficulty utilities
|
│ └── difficulty.ts # Difficulty utilities
|
||||||
├── App.tsx # Root component with routing
|
├── App.tsx # Root component with routing
|
||||||
@@ -149,54 +179,38 @@ frontend/src/
|
|||||||
|
|
||||||
### Route Structure
|
### Route Structure
|
||||||
|
|
||||||
**File**: `App.tsx`
|
|
||||||
|
|
||||||
**Public Routes**:
|
**Public Routes**:
|
||||||
- `/signin` - Sign in page
|
- `/signin` - Sign in page
|
||||||
- `/signup` - Sign up page
|
- `/signup` - Sign up page
|
||||||
|
|
||||||
**Protected Routes** (require authentication):
|
**Protected Routes** (require authentication):
|
||||||
- `/` - Home/Dashboard
|
- `/` - Home dashboard
|
||||||
- `/planner` - Planner Dashboard
|
- `/planner/*` - Planner module routes
|
||||||
- `/planner/keywords` - Keywords page
|
- `/writer/*` - Writer module routes
|
||||||
- `/planner/clusters` - Clusters page
|
- `/thinker/*` - Thinker module routes
|
||||||
- `/planner/ideas` - Ideas page
|
- `/billing/*` - Billing module routes
|
||||||
- `/writer` - Writer Dashboard
|
- `/settings/*` - Settings routes
|
||||||
- `/writer/tasks` - Tasks page
|
- `/help/*` - Help routes
|
||||||
- `/writer/content` - Drafts page
|
- `/reference/*` - Reference data routes
|
||||||
- `/writer/images` - Images page
|
- `/ui-elements/*` - UI element examples
|
||||||
- `/writer/published` - Published page
|
|
||||||
- `/thinker` - Thinker Dashboard
|
### ProtectedRoute Component
|
||||||
- `/thinker/prompts` - Prompts page
|
|
||||||
- `/thinker/author-profiles` - Author Profiles page
|
**Purpose**: Wraps protected routes and checks authentication
|
||||||
- `/thinker/strategies` - Strategies page
|
|
||||||
- `/thinker/image-testing` - Image Testing page
|
**Functionality**:
|
||||||
- `/billing/credits` - Credits page
|
- Checks if user is authenticated
|
||||||
- `/billing/transactions` - Transactions page
|
- Redirects to `/signin` if not authenticated
|
||||||
- `/billing/usage` - Usage page
|
- Wraps children with `AppLayout` if authenticated
|
||||||
- `/settings` - Settings pages
|
|
||||||
- `/analytics` - Analytics page
|
|
||||||
- `/schedules` - Schedules page
|
|
||||||
|
|
||||||
### Route Configuration
|
### Route Configuration
|
||||||
|
|
||||||
**File**: `config/routes.config.ts`
|
**File**: `config/routes.config.ts`
|
||||||
|
|
||||||
Defines route metadata including:
|
**Structure**: Defines route hierarchy, labels, and icons for navigation
|
||||||
- Route paths
|
|
||||||
- Labels for navigation
|
|
||||||
- Icons
|
|
||||||
- Breadcrumb labels
|
|
||||||
- Nested route structure
|
|
||||||
|
|
||||||
### Protected Routes
|
**Functions**:
|
||||||
|
- `getBreadcrumbs(pathname)`: Generates breadcrumbs for current route
|
||||||
**Component**: `components/auth/ProtectedRoute.tsx`
|
|
||||||
|
|
||||||
**Functionality**:
|
|
||||||
- Checks authentication status from `authStore`
|
|
||||||
- Redirects to `/signin` if not authenticated
|
|
||||||
- Wraps protected routes with `AppLayout`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -204,18 +218,7 @@ Defines route metadata including:
|
|||||||
|
|
||||||
### 1. DashboardTemplate
|
### 1. DashboardTemplate
|
||||||
|
|
||||||
**Purpose**: Module home pages with KPIs, workflow steps, and charts.
|
**Purpose**: Module home pages with KPIs, workflow steps, and charts
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
<DashboardTemplate
|
|
||||||
title="Planner Dashboard"
|
|
||||||
subtitle="Manage your SEO keywords and content planning"
|
|
||||||
metrics={metrics}
|
|
||||||
workflowSteps={steps}
|
|
||||||
charts={charts}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Header metrics (KPIs)
|
- Header metrics (KPIs)
|
||||||
@@ -223,24 +226,11 @@ Defines route metadata including:
|
|||||||
- Charts and visualizations
|
- Charts and visualizations
|
||||||
- Quick actions
|
- Quick actions
|
||||||
|
|
||||||
|
**Usage**: Planner Dashboard, Writer Dashboard, Thinker Dashboard
|
||||||
|
|
||||||
### 2. TablePageTemplate
|
### 2. TablePageTemplate
|
||||||
|
|
||||||
**Purpose**: CRUD table pages (Keywords, Clusters, Tasks, etc.).
|
**Purpose**: CRUD table pages (Keywords, Clusters, Tasks, etc.)
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
<TablePageTemplate
|
|
||||||
title="Keywords"
|
|
||||||
subtitle="Manage and organize SEO keywords"
|
|
||||||
columns={columns}
|
|
||||||
data={data}
|
|
||||||
filters={filterConfig}
|
|
||||||
onSort={(field, direction) => ...}
|
|
||||||
onEdit={(row) => ...}
|
|
||||||
onDelete={(row) => ...}
|
|
||||||
bulkActions={bulkActions}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Data table with sorting
|
- Data table with sorting
|
||||||
@@ -257,19 +247,11 @@ Defines route metadata including:
|
|||||||
- `bulkActions`: Bulk action definitions
|
- `bulkActions`: Bulk action definitions
|
||||||
- `actions`: Row action definitions
|
- `actions`: Row action definitions
|
||||||
|
|
||||||
|
**Usage**: Keywords, Clusters, Ideas, Tasks, Content, Images, Prompts, etc.
|
||||||
|
|
||||||
### 3. FormPageTemplate
|
### 3. FormPageTemplate
|
||||||
|
|
||||||
**Purpose**: Settings/form pages (Settings, Integration, etc.).
|
**Purpose**: Settings/form pages (Settings, Integration, etc.)
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
<FormPageTemplate
|
|
||||||
title="Settings"
|
|
||||||
subtitle="Configure your account settings"
|
|
||||||
sections={sections}
|
|
||||||
onSubmit={(data) => ...}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Form sections
|
- Form sections
|
||||||
@@ -277,18 +259,11 @@ Defines route metadata including:
|
|||||||
- Save/Cancel buttons
|
- Save/Cancel buttons
|
||||||
- Success/Error notifications
|
- Success/Error notifications
|
||||||
|
|
||||||
|
**Usage**: Settings, Integration, AI Settings, Plans, etc.
|
||||||
|
|
||||||
### 4. SystemPageTemplate
|
### 4. SystemPageTemplate
|
||||||
|
|
||||||
**Purpose**: System/admin pages (Logs, Status, Monitoring).
|
**Purpose**: System/admin pages (Logs, Status, Monitoring)
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
<SystemPageTemplate
|
|
||||||
title="System Status"
|
|
||||||
subtitle="Monitor system health and performance"
|
|
||||||
content={content}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- System information display
|
- System information display
|
||||||
@@ -296,6 +271,8 @@ Defines route metadata including:
|
|||||||
- Status indicators
|
- Status indicators
|
||||||
- Performance metrics
|
- Performance metrics
|
||||||
|
|
||||||
|
**Usage**: System Status, System Testing, etc.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Component Library
|
## Component Library
|
||||||
@@ -303,9 +280,7 @@ Defines route metadata including:
|
|||||||
### Layout Components
|
### Layout Components
|
||||||
|
|
||||||
#### AppLayout
|
#### AppLayout
|
||||||
**File**: `layout/AppLayout.tsx`
|
**Purpose**: Main app layout wrapper
|
||||||
|
|
||||||
**Purpose**: Main app layout wrapper.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Sidebar navigation
|
- Sidebar navigation
|
||||||
@@ -314,9 +289,7 @@ Defines route metadata including:
|
|||||||
- Breadcrumbs
|
- Breadcrumbs
|
||||||
|
|
||||||
#### Sidebar
|
#### Sidebar
|
||||||
**File**: `components/layout/Sidebar.tsx`
|
**Purpose**: Navigation sidebar
|
||||||
|
|
||||||
**Purpose**: Navigation sidebar.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Module navigation
|
- Module navigation
|
||||||
@@ -324,9 +297,7 @@ Defines route metadata including:
|
|||||||
- Collapsible sections
|
- Collapsible sections
|
||||||
|
|
||||||
#### Header
|
#### Header
|
||||||
**File**: `components/layout/Header.tsx`
|
**Purpose**: Top header bar
|
||||||
|
|
||||||
**Purpose**: Top header bar.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- User menu
|
- User menu
|
||||||
@@ -336,9 +307,7 @@ Defines route metadata including:
|
|||||||
### Table Components
|
### Table Components
|
||||||
|
|
||||||
#### DataTable
|
#### DataTable
|
||||||
**File**: `components/table/DataTable.tsx`
|
**Purpose**: Data table component
|
||||||
|
|
||||||
**Purpose**: Data table component.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Sortable columns
|
- Sortable columns
|
||||||
@@ -347,9 +316,7 @@ Defines route metadata including:
|
|||||||
- Responsive design
|
- Responsive design
|
||||||
|
|
||||||
#### Filters
|
#### Filters
|
||||||
**File**: `components/table/Filters.tsx`
|
**Purpose**: Filter component
|
||||||
|
|
||||||
**Purpose**: Filter component.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Text filters
|
- Text filters
|
||||||
@@ -358,9 +325,7 @@ Defines route metadata including:
|
|||||||
- Custom filters
|
- Custom filters
|
||||||
|
|
||||||
#### Pagination
|
#### Pagination
|
||||||
**File**: `components/ui/pagination/CompactPagination.tsx`
|
**Purpose**: Pagination component
|
||||||
|
|
||||||
**Purpose**: Pagination component.
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Page navigation
|
- Page navigation
|
||||||
@@ -370,52 +335,33 @@ Defines route metadata including:
|
|||||||
### UI Components
|
### UI Components
|
||||||
|
|
||||||
#### Button
|
#### Button
|
||||||
**File**: `components/ui/button/Button.tsx`
|
|
||||||
|
|
||||||
**Variants**: primary, secondary, danger, ghost, link
|
**Variants**: primary, secondary, danger, ghost, link
|
||||||
|
|
||||||
**Sizes**: sm, md, lg
|
**Sizes**: sm, md, lg
|
||||||
|
|
||||||
#### Card
|
#### Card
|
||||||
**File**: `components/ui/card/Card.tsx`
|
**Purpose**: Card container component
|
||||||
|
|
||||||
**Purpose**: Card container component.
|
|
||||||
|
|
||||||
#### Modal
|
#### Modal
|
||||||
**File**: `components/ui/modal/Modal.tsx`
|
**Purpose**: Modal dialog component
|
||||||
|
|
||||||
**Purpose**: Modal dialog component.
|
|
||||||
|
|
||||||
**Variants**: FormModal, ProgressModal, AlertModal
|
**Variants**: FormModal, ProgressModal, AlertModal
|
||||||
|
|
||||||
#### Toast
|
#### Toast
|
||||||
**File**: `components/ui/toast/ToastContainer.tsx`
|
**Purpose**: Toast notification system
|
||||||
|
|
||||||
**Purpose**: Toast notification system.
|
|
||||||
|
|
||||||
**Types**: success, error, warning, info
|
**Types**: success, error, warning, info
|
||||||
|
|
||||||
#### Input
|
#### Input
|
||||||
**File**: `components/form/input/InputField.tsx`
|
**Purpose**: Text input component
|
||||||
|
|
||||||
**Purpose**: Text input component.
|
|
||||||
|
|
||||||
#### Select
|
#### Select
|
||||||
**File**: `components/form/SelectDropdown.tsx`
|
**Purpose**: Select dropdown component
|
||||||
|
|
||||||
**Purpose**: Select dropdown component.
|
|
||||||
|
|
||||||
#### Checkbox
|
#### Checkbox
|
||||||
**File**: `components/form/input/Checkbox.tsx`
|
**Purpose**: Checkbox component
|
||||||
|
|
||||||
**Purpose**: Checkbox component.
|
|
||||||
|
|
||||||
### Auth Components
|
### Auth Components
|
||||||
|
|
||||||
#### ProtectedRoute
|
#### ProtectedRoute
|
||||||
**File**: `components/auth/ProtectedRoute.tsx`
|
**Purpose**: Route protection component
|
||||||
|
|
||||||
**Purpose**: Route protection component.
|
|
||||||
|
|
||||||
**Functionality**:
|
**Functionality**:
|
||||||
- Checks authentication
|
- Checks authentication
|
||||||
@@ -429,8 +375,6 @@ Defines route metadata including:
|
|||||||
### Zustand Stores
|
### Zustand Stores
|
||||||
|
|
||||||
#### authStore
|
#### authStore
|
||||||
**File**: `store/authStore.ts`
|
|
||||||
|
|
||||||
**State**:
|
**State**:
|
||||||
- `user`: Current user object
|
- `user`: Current user object
|
||||||
- `token`: JWT access token
|
- `token`: JWT access token
|
||||||
@@ -448,16 +392,7 @@ Defines route metadata including:
|
|||||||
|
|
||||||
**Persistence**: localStorage (persisted)
|
**Persistence**: localStorage (persisted)
|
||||||
|
|
||||||
#### plannerStore
|
|
||||||
**File**: `store/plannerStore.ts`
|
|
||||||
|
|
||||||
**State**: Planner module-specific state
|
|
||||||
|
|
||||||
**Actions**: Planner module actions
|
|
||||||
|
|
||||||
#### siteStore
|
#### siteStore
|
||||||
**File**: `store/siteStore.ts`
|
|
||||||
|
|
||||||
**State**:
|
**State**:
|
||||||
- `activeSite`: Currently selected site
|
- `activeSite`: Currently selected site
|
||||||
- `sites`: List of accessible sites
|
- `sites`: List of accessible sites
|
||||||
@@ -469,8 +404,6 @@ Defines route metadata including:
|
|||||||
**Persistence**: localStorage (persisted)
|
**Persistence**: localStorage (persisted)
|
||||||
|
|
||||||
#### sectorStore
|
#### sectorStore
|
||||||
**File**: `store/sectorStore.ts`
|
|
||||||
|
|
||||||
**State**:
|
**State**:
|
||||||
- `activeSector`: Currently selected sector
|
- `activeSector`: Currently selected sector
|
||||||
- `sectors`: List of sectors for active site
|
- `sectors`: List of sectors for active site
|
||||||
@@ -481,9 +414,12 @@ Defines route metadata including:
|
|||||||
|
|
||||||
**Persistence**: localStorage (persisted)
|
**Persistence**: localStorage (persisted)
|
||||||
|
|
||||||
#### aiRequestLogsStore
|
#### plannerStore
|
||||||
**File**: `store/aiRequestLogsStore.ts`
|
**State**: Planner module-specific state
|
||||||
|
|
||||||
|
**Actions**: Planner module actions
|
||||||
|
|
||||||
|
#### aiRequestLogsStore
|
||||||
**State**:
|
**State**:
|
||||||
- `logs`: Array of AI request/response logs
|
- `logs`: Array of AI request/response logs
|
||||||
|
|
||||||
@@ -497,8 +433,6 @@ Defines route metadata including:
|
|||||||
**Purpose**: Tracks AI function execution with step-by-step logs
|
**Purpose**: Tracks AI function execution with step-by-step logs
|
||||||
|
|
||||||
#### pageSizeStore
|
#### pageSizeStore
|
||||||
**File**: `store/pageSizeStore.ts`
|
|
||||||
|
|
||||||
**State**:
|
**State**:
|
||||||
- `pageSize`: Table page size preference
|
- `pageSize`: Table page size preference
|
||||||
|
|
||||||
@@ -556,29 +490,16 @@ Defines route metadata including:
|
|||||||
|
|
||||||
**Example**: `keywords.config.tsx`
|
**Example**: `keywords.config.tsx`
|
||||||
|
|
||||||
**Structure**:
|
**Structure**: Defines columns, filters, bulkActions, actions for a page
|
||||||
```tsx
|
|
||||||
export const createKeywordsPageConfig = () => ({
|
|
||||||
columns: [...],
|
|
||||||
filters: [...],
|
|
||||||
bulkActions: [...],
|
|
||||||
actions: [...],
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**Usage**:
|
**Usage**: Imported in page components to configure TablePageTemplate
|
||||||
```tsx
|
|
||||||
import { createKeywordsPageConfig } from '../../config/pages/keywords.config';
|
|
||||||
|
|
||||||
const config = createKeywordsPageConfig();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Shared Snippets
|
### Shared Snippets
|
||||||
|
|
||||||
**Location**: `config/snippets/`
|
**Location**: `config/snippets/`
|
||||||
|
|
||||||
#### columns.snippets.ts
|
#### columns.snippets.ts
|
||||||
**Purpose**: Reusable column definitions.
|
**Purpose**: Reusable column definitions
|
||||||
|
|
||||||
**Examples**:
|
**Examples**:
|
||||||
- `statusColumn`: Status column with badge
|
- `statusColumn`: Status column with badge
|
||||||
@@ -586,7 +507,7 @@ const config = createKeywordsPageConfig();
|
|||||||
- `dateColumn`: Date column with formatting
|
- `dateColumn`: Date column with formatting
|
||||||
|
|
||||||
#### filters.snippets.ts
|
#### filters.snippets.ts
|
||||||
**Purpose**: Reusable filter definitions.
|
**Purpose**: Reusable filter definitions
|
||||||
|
|
||||||
**Examples**:
|
**Examples**:
|
||||||
- `statusFilter`: Status dropdown filter
|
- `statusFilter`: Status dropdown filter
|
||||||
@@ -594,7 +515,7 @@ const config = createKeywordsPageConfig();
|
|||||||
- `searchFilter`: Text search filter
|
- `searchFilter`: Text search filter
|
||||||
|
|
||||||
#### actions.snippets.ts
|
#### actions.snippets.ts
|
||||||
**Purpose**: Reusable action definitions.
|
**Purpose**: Reusable action definitions
|
||||||
|
|
||||||
**Examples**:
|
**Examples**:
|
||||||
- `commonActions`: Edit, Delete actions
|
- `commonActions`: Edit, Delete actions
|
||||||
@@ -604,34 +525,18 @@ const config = createKeywordsPageConfig();
|
|||||||
|
|
||||||
**File**: `config/routes.config.ts`
|
**File**: `config/routes.config.ts`
|
||||||
|
|
||||||
**Structure**:
|
**Structure**: Defines route hierarchy, labels, and icons for navigation
|
||||||
```tsx
|
|
||||||
export const routes: RouteConfig[] = [
|
|
||||||
{
|
|
||||||
path: '/planner',
|
|
||||||
label: 'Planner',
|
|
||||||
icon: 'Planner',
|
|
||||||
children: [
|
|
||||||
{ path: '/planner/keywords', label: 'Keywords' },
|
|
||||||
...
|
|
||||||
],
|
|
||||||
},
|
|
||||||
...
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**Functions**:
|
**Functions**:
|
||||||
- `getBreadcrumbs(pathname)`: Get breadcrumbs for current route
|
- `getBreadcrumbs(pathname)`: Generates breadcrumbs for current route
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Pages
|
## Pages & Features
|
||||||
|
|
||||||
### Planner Module
|
### Planner Module
|
||||||
|
|
||||||
#### Keywords Page
|
#### Keywords Page (`/planner/keywords`)
|
||||||
**File**: `pages/Planner/Keywords.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Keyword CRUD operations
|
- Keyword CRUD operations
|
||||||
- Auto-cluster functionality
|
- Auto-cluster functionality
|
||||||
@@ -642,28 +547,28 @@ export const routes: RouteConfig[] = [
|
|||||||
|
|
||||||
**Configuration**: Uses `keywords.config.tsx`
|
**Configuration**: Uses `keywords.config.tsx`
|
||||||
|
|
||||||
#### Clusters Page
|
#### Clusters Page (`/planner/clusters`)
|
||||||
**File**: `pages/Planner/Clusters.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Cluster CRUD operations
|
- Cluster CRUD operations
|
||||||
- Auto-generate ideas functionality
|
- Auto-generate ideas functionality
|
||||||
- Filters (status, sector)
|
- Filters (status, sector)
|
||||||
- Bulk actions
|
- Bulk actions
|
||||||
|
|
||||||
#### Ideas Page
|
#### Ideas Page (`/planner/ideas`)
|
||||||
**File**: `pages/Planner/Ideas.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Content ideas CRUD operations
|
- Content ideas CRUD operations
|
||||||
- Filters (status, cluster, content type)
|
- Filters (status, cluster, content type)
|
||||||
- Bulk actions
|
- Bulk actions
|
||||||
|
|
||||||
|
#### Planner Dashboard (`/planner`)
|
||||||
|
**Features**:
|
||||||
|
- KPIs (total keywords, clusters, ideas)
|
||||||
|
- Workflow steps
|
||||||
|
- Charts and visualizations
|
||||||
|
|
||||||
### Writer Module
|
### Writer Module
|
||||||
|
|
||||||
#### Tasks Page
|
#### Tasks Page (`/writer/tasks`)
|
||||||
**File**: `pages/Writer/Tasks.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Task CRUD operations
|
- Task CRUD operations
|
||||||
- Auto-generate content functionality
|
- Auto-generate content functionality
|
||||||
@@ -671,105 +576,145 @@ export const routes: RouteConfig[] = [
|
|||||||
- Filters (status, cluster, content type)
|
- Filters (status, cluster, content type)
|
||||||
- Bulk actions
|
- Bulk actions
|
||||||
|
|
||||||
|
#### Content Page (`/writer/content`)
|
||||||
|
**Features**:
|
||||||
|
- Content list view
|
||||||
|
- Content detail view (`/writer/content/:id`)
|
||||||
|
- Content editing
|
||||||
|
- Generate image prompts
|
||||||
|
- Generate images
|
||||||
|
- WordPress publishing
|
||||||
|
|
||||||
|
#### Images Page (`/writer/images`)
|
||||||
|
**Features**:
|
||||||
|
- Image list view
|
||||||
|
- Image generation
|
||||||
|
- Image management
|
||||||
|
|
||||||
|
#### Writer Dashboard (`/writer`)
|
||||||
|
**Features**:
|
||||||
|
- KPIs (total tasks, content, images)
|
||||||
|
- Workflow steps
|
||||||
|
- Charts and visualizations
|
||||||
|
|
||||||
|
### Thinker Module
|
||||||
|
|
||||||
|
#### Prompts Page (`/thinker/prompts`)
|
||||||
|
**Features**:
|
||||||
|
- AI prompt CRUD operations
|
||||||
|
- Prompt type management
|
||||||
|
- Default prompt reset
|
||||||
|
|
||||||
|
#### Author Profiles Page (`/thinker/author-profiles`)
|
||||||
|
**Features**:
|
||||||
|
- Author profile CRUD operations
|
||||||
|
- Writing style configuration
|
||||||
|
|
||||||
|
#### Strategies Page (`/thinker/strategies`)
|
||||||
|
**Features**:
|
||||||
|
- Content strategy CRUD operations
|
||||||
|
- Strategy configuration
|
||||||
|
|
||||||
|
#### Image Testing Page (`/thinker/image-testing`)
|
||||||
|
**Features**:
|
||||||
|
- Image generation testing
|
||||||
|
- Prompt testing
|
||||||
|
- Model testing
|
||||||
|
|
||||||
|
### Billing Module
|
||||||
|
|
||||||
|
#### Credits Page (`/billing/credits`)
|
||||||
|
**Features**:
|
||||||
|
- Credit balance display
|
||||||
|
- Credit purchase
|
||||||
|
- Credit history
|
||||||
|
|
||||||
|
#### Transactions Page (`/billing/transactions`)
|
||||||
|
**Features**:
|
||||||
|
- Transaction history
|
||||||
|
- Transaction filtering
|
||||||
|
|
||||||
|
#### Usage Page (`/billing/usage`)
|
||||||
|
**Features**:
|
||||||
|
- Usage logs
|
||||||
|
- Cost tracking
|
||||||
|
- Usage analytics
|
||||||
|
|
||||||
### Settings Pages
|
### Settings Pages
|
||||||
|
|
||||||
#### Sites Page
|
#### Sites Page (`/settings/sites`)
|
||||||
**File**: `pages/Settings/Sites.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Site CRUD operations
|
- Site CRUD operations
|
||||||
- Site activation/deactivation
|
- Site activation/deactivation
|
||||||
- Multiple sites can be active simultaneously
|
- Multiple sites can be active simultaneously
|
||||||
|
|
||||||
#### Integration Page
|
#### Integration Page (`/settings/integration`)
|
||||||
**File**: `pages/Settings/Integration.tsx`
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Integration settings (OpenAI, Runware)
|
- Integration settings (OpenAI, Runware)
|
||||||
- API key configuration
|
- API key configuration
|
||||||
- Test connections
|
- Test connections
|
||||||
- Image generation testing
|
- Image generation testing
|
||||||
|
|
||||||
|
#### Users Page (`/settings/users`)
|
||||||
|
**Features**:
|
||||||
|
- User CRUD operations
|
||||||
|
- Role management
|
||||||
|
- Site access management
|
||||||
|
|
||||||
|
#### AI Settings Page (`/settings/ai`)
|
||||||
|
**Features**:
|
||||||
|
- AI prompt management
|
||||||
|
- Model configuration
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hooks
|
## Hooks & Utilities
|
||||||
|
|
||||||
### useProgressModal
|
### useProgressModal
|
||||||
|
|
||||||
**File**: `hooks/useProgressModal.ts`
|
**Purpose**: Progress modal for long-running AI tasks
|
||||||
|
|
||||||
**Purpose**: Progress modal for long-running Celery tasks.
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
const progressModal = useProgressModal();
|
|
||||||
|
|
||||||
// Start task
|
|
||||||
progressModal.start(taskId, 'Task started...');
|
|
||||||
|
|
||||||
// Task progress is automatically polled
|
|
||||||
// Modal displays progress updates
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Automatic polling of task progress
|
- Displays progress percentage
|
||||||
- Progress percentage display
|
- Shows phase messages
|
||||||
- Step-by-step logs (request/response steps)
|
- Displays request/response steps
|
||||||
- Success/Error handling
|
- Shows cost and token information
|
||||||
- Auto-close on completion
|
- Auto-closes on completion
|
||||||
|
|
||||||
### useAuth
|
### useAuth
|
||||||
|
|
||||||
**File**: `hooks/useAuth.ts`
|
**Purpose**: Authentication hook
|
||||||
|
|
||||||
**Purpose**: Authentication hook.
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```tsx
|
|
||||||
const { user, isAuthenticated, login, logout } = useAuth();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Access to auth state
|
- Checks authentication status
|
||||||
- Login/logout functions
|
- Provides user information
|
||||||
- Authentication status
|
- Handles token refresh
|
||||||
|
|
||||||
---
|
### Utilities
|
||||||
|
|
||||||
## Utilities
|
#### difficulty.ts
|
||||||
|
**Purpose**: Difficulty calculation utilities
|
||||||
### Difficulty Utilities
|
|
||||||
|
|
||||||
**File**: `utils/difficulty.ts`
|
|
||||||
|
|
||||||
**Functions**:
|
**Functions**:
|
||||||
- `getDifficultyLabelFromNumber(number)`: Get difficulty label (Easy, Medium, Hard)
|
- Difficulty level calculation
|
||||||
- `getDifficultyRange()`: Get difficulty range options
|
- Difficulty formatting
|
||||||
|
|
||||||
### API Utilities
|
|
||||||
|
|
||||||
**File**: `services/api.ts`
|
|
||||||
|
|
||||||
**Helper Functions**:
|
|
||||||
- `getActiveSiteId()`: Get active site ID from store
|
|
||||||
- `getActiveSectorId()`: Get active sector ID from store
|
|
||||||
- `getAuthToken()`: Get JWT token from store
|
|
||||||
- `getRefreshToken()`: Get refresh token from store
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
The IGNY8 frontend is built on:
|
The IGNY8 frontend provides:
|
||||||
|
|
||||||
1. **Configuration-Driven Architecture**: Zero duplication, single source of truth
|
1. **Configuration-Driven UI**: All pages rendered from configuration
|
||||||
2. **4 Universal Templates**: Reusable templates for all page types
|
2. **4 Universal Templates**: Reusable templates for all page types
|
||||||
3. **TypeScript**: Full type safety
|
3. **TypeScript**: Full type safety
|
||||||
4. **Zustand State Management**: Lightweight, performant state management
|
4. **Zustand State Management**: Lightweight, performant state
|
||||||
5. **React Router v6**: Modern routing with nested routes
|
5. **React Router v6**: Modern routing
|
||||||
6. **Component Library**: Reusable UI components
|
6. **Component Library**: Comprehensive UI components
|
||||||
7. **API Integration**: Automatic token handling and error management
|
7. **API Integration**: Automatic token handling and retry
|
||||||
8. **Responsive Design**: Mobile-first with Tailwind CSS
|
8. **Progress Tracking**: Real-time progress for AI tasks
|
||||||
|
9. **Responsive Design**: Mobile-first approach
|
||||||
|
10. **Complete Feature Set**: All modules and pages implemented
|
||||||
|
|
||||||
This architecture ensures consistency, maintainability, and extensibility while providing a great user experience.
|
This architecture ensures consistency, maintainability, and rapid feature development while providing a great user experience.
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
# IGNY8 Backend Documentation
|
# IGNY8 Backend Documentation
|
||||||
|
|
||||||
**Version:** 1.0
|
|
||||||
**Last Updated:** 2025-01-XX
|
**Last Updated:** 2025-01-XX
|
||||||
**Purpose:** Complete backend documentation covering models, views, APIs, modules, serializers, tasks, and structure.
|
**Purpose:** Complete backend documentation covering models, views, APIs, modules, serializers, tasks, and structure.
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ The IGNY8 backend is a Django 5.2+ application using Django REST Framework (DRF)
|
|||||||
- **RESTful API**: DRF ViewSets with consistent response format
|
- **RESTful API**: DRF ViewSets with consistent response format
|
||||||
- **Celery Integration**: Asynchronous task processing for long-running operations
|
- **Celery Integration**: Asynchronous task processing for long-running operations
|
||||||
- **Account/Site/Sector Hierarchy**: Hierarchical data organization
|
- **Account/Site/Sector Hierarchy**: Hierarchical data organization
|
||||||
- **AI Integration**: Unified AIProcessor for all AI operations
|
- **AI Integration**: Unified AI framework for all AI operations
|
||||||
- **Progress Tracking**: Real-time progress updates for Celery tasks
|
- **Progress Tracking**: Real-time progress updates for Celery tasks
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -75,7 +74,7 @@ backend/igny8_core/
|
|||||||
│ │ └── urls.py # Planner module URLs
|
│ │ └── urls.py # Planner module URLs
|
||||||
│ ├── writer/ # Tasks, Content, Images
|
│ ├── writer/ # Tasks, Content, Images
|
||||||
│ │ ├── models.py # Tasks, Content, Images models
|
│ │ ├── models.py # Tasks, Content, Images models
|
||||||
│ │ ├── views.py # TasksViewSet
|
│ │ ├── views.py # TasksViewSet, ImagesViewSet
|
||||||
│ │ ├── tasks.py # Celery tasks for content/image generation
|
│ │ ├── tasks.py # Celery tasks for content/image generation
|
||||||
│ │ └── urls.py # Writer module URLs
|
│ │ └── urls.py # Writer module URLs
|
||||||
│ ├── system/ # Settings, Prompts, Integration
|
│ ├── system/ # Settings, Prompts, Integration
|
||||||
@@ -85,18 +84,34 @@ backend/igny8_core/
|
|||||||
│ │ ├── utils.py # Default prompts, prompt loading
|
│ │ ├── utils.py # Default prompts, prompt loading
|
||||||
│ │ └── urls.py # System module URLs
|
│ │ └── urls.py # System module URLs
|
||||||
│ └── billing/ # Credits, Transactions, Usage
|
│ └── billing/ # Credits, Transactions, Usage
|
||||||
│ ├── models.py # CreditTransaction, UsageLog models
|
│ ├── models.py # CreditTransaction, CreditUsageLog models
|
||||||
│ ├── views.py # Billing ViewSets
|
│ ├── views.py # Billing ViewSets
|
||||||
│ └── services.py # CreditService
|
│ └── services.py # CreditService
|
||||||
├── api/ # API base classes
|
├── api/ # API base classes
|
||||||
│ ├── base.py # AccountModelViewSet, SiteSectorModelViewSet
|
│ ├── base.py # AccountModelViewSet, SiteSectorModelViewSet
|
||||||
│ └── pagination.py # CustomPageNumberPagination
|
│ └── pagination.py # CustomPageNumberPagination
|
||||||
├── utils/ # Shared utilities
|
├── utils/ # Shared utilities
|
||||||
│ ├── ai_processor.py # Unified AI interface
|
│ ├── ai_processor.py # Unified AI interface (legacy, see AI functions)
|
||||||
│ └── content_normalizer.py # Content processing utilities
|
│ └── content_normalizer.py # Content processing utilities
|
||||||
├── middleware/ # Custom middleware
|
├── middleware/ # Custom middleware
|
||||||
│ ├── account.py # AccountContextMiddleware (sets request.account)
|
│ ├── account.py # AccountContextMiddleware (sets request.account)
|
||||||
│ └── resource_tracker.py # ResourceTrackerMiddleware (API metrics)
|
│ └── resource_tracker.py # ResourceTrackerMiddleware (API metrics)
|
||||||
|
├── ai/ # AI framework
|
||||||
|
│ ├── base.py # BaseAIFunction
|
||||||
|
│ ├── engine.py # AIEngine
|
||||||
|
│ ├── tasks.py # run_ai_task
|
||||||
|
│ ├── registry.py # Function registry
|
||||||
|
│ ├── prompts.py # PromptRegistry
|
||||||
|
│ ├── ai_core.py # AICore
|
||||||
|
│ ├── settings.py # Model configuration
|
||||||
|
│ ├── validators.py # Validation functions
|
||||||
|
│ ├── tracker.py # Progress tracking
|
||||||
|
│ └── functions/ # AI function implementations
|
||||||
|
│ ├── auto_cluster.py
|
||||||
|
│ ├── generate_ideas.py
|
||||||
|
│ ├── generate_content.py
|
||||||
|
│ ├── generate_image_prompts.py
|
||||||
|
│ └── generate_images.py
|
||||||
├── settings.py # Django settings
|
├── settings.py # Django settings
|
||||||
├── urls.py # Root URL configuration
|
├── urls.py # Root URL configuration
|
||||||
└── celery.py # Celery configuration
|
└── celery.py # Celery configuration
|
||||||
@@ -120,7 +135,6 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**Usage**: All models that need account isolation inherit from this.
|
**Usage**: All models that need account isolation inherit from this.
|
||||||
|
|
||||||
|
|
||||||
#### SiteSectorBaseModel
|
#### SiteSectorBaseModel
|
||||||
**File**: `auth/models.py`
|
**File**: `auth/models.py`
|
||||||
|
|
||||||
@@ -139,266 +153,207 @@ backend/igny8_core/
|
|||||||
### Auth Models
|
### Auth Models
|
||||||
|
|
||||||
#### Account
|
#### Account
|
||||||
**File**: `auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_accounts`
|
**Table**: `igny8_accounts`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- `name`: CharField
|
- `name`: CharField
|
||||||
- `slug`: SlugField (unique)
|
- `slug`: SlugField (unique)
|
||||||
- `owner`: ForeignKey to User
|
- `owner`: ForeignKey to User
|
||||||
- `stripe_customer_id`: CharField (optional)
|
|
||||||
- `plan`: ForeignKey to Plan
|
- `plan`: ForeignKey to Plan
|
||||||
- `credits`: IntegerField (default: 0)
|
- `credits`: IntegerField (default: 0)
|
||||||
- `status`: CharField (choices: active, suspended, trial, cancelled)
|
- `status`: CharField (choices: active, suspended, trial, cancelled)
|
||||||
|
|
||||||
**Methods**:
|
**Methods**:
|
||||||
- `is_system_account()`: Returns True if account is system account (aws-admin, default-account, default)
|
- `is_system_account()`: Returns True if account is a system account
|
||||||
|
|
||||||
#### User
|
#### User
|
||||||
**File**: `auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_users`
|
**Table**: `igny8_users`
|
||||||
|
|
||||||
|
**Inherits**: `AbstractUser`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `AbstractUser`
|
- `email`: EmailField (unique)
|
||||||
- `email`: EmailField (unique, USERNAME_FIELD)
|
|
||||||
- `account`: ForeignKey to Account
|
- `account`: ForeignKey to Account
|
||||||
- `role`: CharField (choices: developer, owner, admin, editor, viewer, system_bot)
|
- `role`: CharField (choices: developer, owner, admin, editor, viewer, system_bot)
|
||||||
|
|
||||||
**Methods**:
|
**Methods**:
|
||||||
- `has_role(*roles)`: Check if user has any of the specified roles
|
- `has_role(role)`: Checks if user has role
|
||||||
- `is_owner_or_admin()`: Returns True if role is owner or admin
|
- `is_owner_or_admin()`: Checks if user is owner or admin
|
||||||
- `is_developer()`: Returns True if role is developer or is_superuser
|
- `is_developer()`: Checks if user is developer
|
||||||
- `is_admin_or_developer()`: Returns True if role is admin or developer
|
- `is_admin_or_developer()`: Checks if user is admin or developer
|
||||||
- `is_system_account_user()`: Returns True if user belongs to system account
|
- `is_system_account_user()`: Checks if user belongs to system account
|
||||||
- `get_accessible_sites()`: Returns QuerySet of sites user can access
|
- `get_accessible_sites()`: Returns queryset of accessible sites
|
||||||
|
|
||||||
#### Plan
|
#### Plan
|
||||||
**File**: `auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_plans`
|
**Table**: `igny8_plans`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**: Extensive fields for limits (users, sites, keywords, clusters, content ideas, AI requests, word count, images, credits)
|
||||||
- `name`: CharField
|
|
||||||
- `slug`: SlugField (unique)
|
|
||||||
- `price`: DecimalField
|
|
||||||
- `billing_cycle`: CharField (choices: monthly, annual)
|
|
||||||
- `features`: JSONField (array of feature strings)
|
|
||||||
- `max_users`: IntegerField
|
|
||||||
- `max_sites`: IntegerField
|
|
||||||
- `max_keywords`: IntegerField
|
|
||||||
- `max_clusters`: IntegerField
|
|
||||||
- `max_content_ideas`: IntegerField
|
|
||||||
- `daily_cluster_limit`: IntegerField
|
|
||||||
- `monthly_cluster_ai_credits`: IntegerField
|
|
||||||
- `daily_content_tasks`: IntegerField
|
|
||||||
- `daily_ai_requests`: IntegerField
|
|
||||||
- `monthly_word_count_limit`: IntegerField
|
|
||||||
- `monthly_content_ai_credits`: IntegerField
|
|
||||||
- `monthly_image_count`: IntegerField
|
|
||||||
- `daily_image_generation_limit`: IntegerField
|
|
||||||
- `monthly_image_ai_credits`: IntegerField
|
|
||||||
- `max_images_per_task`: IntegerField
|
|
||||||
- `image_model_choices`: JSONField
|
|
||||||
- `included_credits`: IntegerField
|
|
||||||
- `extra_credit_price`: DecimalField
|
|
||||||
- And more...
|
|
||||||
|
|
||||||
**Methods**:
|
**Methods**:
|
||||||
- `clean()`: Validates plan limits
|
- `clean()`: Validates plan limits
|
||||||
- `get_effective_credits_per_month()`: Returns included_credits or credits_per_month
|
- `get_effective_credits_per_month()`: Returns included_credits or credits_per_month
|
||||||
|
|
||||||
#### Site
|
#### Site
|
||||||
**File**: `auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_sites`
|
**Table**: `igny8_sites`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `name`: CharField
|
- `name`: CharField
|
||||||
- `slug`: SlugField (unique per account)
|
- `slug`: SlugField (unique per account)
|
||||||
- `domain`: URLField (optional)
|
- `domain`: URLField (optional)
|
||||||
- `industry`: ForeignKey to Industry (optional)
|
- `industry`: ForeignKey to Industry (optional)
|
||||||
- `is_active`: BooleanField
|
- `is_active`: BooleanField
|
||||||
- `status`: CharField (choices: active, inactive, suspended)
|
- `status`: CharField
|
||||||
- `wp_url`: URLField (optional, WordPress integration)
|
- `wp_url`: URLField (optional)
|
||||||
- `wp_username`: CharField (optional)
|
- `wp_username`: CharField (optional)
|
||||||
- `wp_app_password`: CharField (optional)
|
- `wp_app_password`: CharField (optional)
|
||||||
|
|
||||||
**Methods**:
|
**Methods**:
|
||||||
- `get_active_sectors_count()`: Get count of active sectors
|
- `get_active_sectors_count()`: Returns count of active sectors
|
||||||
- `can_add_sector()`: Check if site can add another sector (max 5)
|
- `can_add_sector()`: Returns True if site can add another sector (max 5)
|
||||||
|
|
||||||
#### Sector
|
#### Sector
|
||||||
**File**: `auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_sectors`
|
**Table**: `igny8_sectors`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `site`: ForeignKey to Site
|
- `site`: ForeignKey to Site
|
||||||
- `industry_sector`: ForeignKey to IndustrySector (optional, template reference)
|
- `industry_sector`: ForeignKey to IndustrySector (optional)
|
||||||
- `name`: CharField
|
- `name`: CharField
|
||||||
- `slug`: SlugField (unique per site)
|
- `slug`: SlugField (unique per site)
|
||||||
- `is_active`: BooleanField
|
- `is_active`: BooleanField
|
||||||
- `status`: CharField (choices: active, inactive)
|
- `status`: CharField
|
||||||
|
|
||||||
|
**Validation**: Maximum 5 active sectors per site
|
||||||
|
|
||||||
### Planner Models
|
### Planner Models
|
||||||
|
|
||||||
#### Keywords
|
#### Keywords
|
||||||
**File**: `modules/planner/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_keywords`
|
**Table**: `igny8_keywords`
|
||||||
|
|
||||||
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `SiteSectorBaseModel`
|
|
||||||
- `keyword`: CharField
|
- `keyword`: CharField
|
||||||
- `volume`: IntegerField
|
- `volume`: IntegerField (optional)
|
||||||
- `difficulty`: IntegerField
|
- `difficulty`: IntegerField (optional)
|
||||||
- `intent`: CharField (choices: informational, navigational, commercial, transactional)
|
- `intent`: CharField (optional)
|
||||||
- `cluster`: ForeignKey to Clusters (optional)
|
- `status`: CharField
|
||||||
- `status`: CharField (choices: active, pending, archived)
|
- `cluster`: ManyToManyField to Clusters
|
||||||
|
|
||||||
#### Clusters
|
#### Clusters
|
||||||
**File**: `modules/planner/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_clusters`
|
**Table**: `igny8_clusters`
|
||||||
|
|
||||||
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `SiteSectorBaseModel`
|
- `name`: CharField
|
||||||
- `name`: CharField (unique)
|
- `description`: TextField (optional)
|
||||||
- `description`: TextField
|
- `keywords_count`: IntegerField (calculated)
|
||||||
- `keywords_count`: IntegerField
|
- `volume`: IntegerField (calculated)
|
||||||
- `volume`: IntegerField
|
|
||||||
- `mapped_pages`: IntegerField
|
|
||||||
- `status`: CharField
|
- `status`: CharField
|
||||||
|
- `keywords`: ManyToManyField to Keywords
|
||||||
|
|
||||||
#### ContentIdeas
|
#### ContentIdeas
|
||||||
**File**: `modules/planner/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_content_ideas`
|
**Table**: `igny8_content_ideas`
|
||||||
|
|
||||||
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `SiteSectorBaseModel`
|
|
||||||
- `idea_title`: CharField
|
- `idea_title`: CharField
|
||||||
- `description`: TextField
|
- `description`: TextField
|
||||||
- `content_structure`: CharField (choices: cluster_hub, landing_page, pillar_page, supporting_page)
|
- `content_type`: CharField
|
||||||
- `content_type`: CharField (choices: blog_post, article, guide, tutorial)
|
- `content_structure`: CharField
|
||||||
- `target_keywords`: CharField (comma-separated, legacy)
|
- `target_keywords`: TextField
|
||||||
- `keyword_objects`: ManyToManyField to Keywords
|
|
||||||
- `keyword_cluster`: ForeignKey to Clusters
|
- `keyword_cluster`: ForeignKey to Clusters
|
||||||
- `status`: CharField (choices: new, scheduled, published)
|
|
||||||
- `estimated_word_count`: IntegerField
|
- `estimated_word_count`: IntegerField
|
||||||
|
- `status`: CharField
|
||||||
|
|
||||||
### Writer Models
|
### Writer Models
|
||||||
|
|
||||||
#### Tasks
|
#### Tasks
|
||||||
**File**: `modules/writer/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_tasks`
|
**Table**: `igny8_tasks`
|
||||||
|
|
||||||
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `SiteSectorBaseModel`
|
|
||||||
- `title`: CharField
|
- `title`: CharField
|
||||||
- `description`: TextField
|
- `description`: TextField
|
||||||
- `keywords`: CharField (comma-separated, legacy)
|
- `cluster`: ForeignKey to Clusters (optional)
|
||||||
- `keyword_objects`: ManyToManyField to Keywords
|
- `idea`: ForeignKey to ContentIdeas (optional)
|
||||||
- `cluster`: ForeignKey to Clusters
|
|
||||||
- `idea`: ForeignKey to ContentIdeas
|
|
||||||
- `content_structure`: CharField
|
|
||||||
- `content_type`: CharField
|
- `content_type`: CharField
|
||||||
- `status`: CharField (choices: queued, in_progress, draft, review, published, completed)
|
- `content_structure`: CharField
|
||||||
- `content`: TextField (generated content)
|
- `status`: CharField
|
||||||
- `word_count`: IntegerField
|
|
||||||
- `meta_title`: CharField
|
|
||||||
- `meta_description`: TextField
|
|
||||||
- `assigned_post_id`: IntegerField (WordPress post ID)
|
|
||||||
- `post_url`: URLField
|
|
||||||
|
|
||||||
#### Content
|
#### Content
|
||||||
**File**: `modules/writer/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_content`
|
**Table**: `igny8_content`
|
||||||
|
|
||||||
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `SiteSectorBaseModel`
|
|
||||||
- `task`: OneToOneField to Tasks
|
- `task`: OneToOneField to Tasks
|
||||||
- `html_content`: TextField
|
- `html_content`: TextField
|
||||||
- `word_count`: IntegerField
|
- `word_count`: IntegerField
|
||||||
- `metadata`: JSONField
|
- `status`: CharField
|
||||||
|
- `wp_post_id`: IntegerField (optional)
|
||||||
**Methods**:
|
- `meta_title`: CharField (optional)
|
||||||
- `save()`: Automatically sets account, site, sector from task
|
- `meta_description`: TextField (optional)
|
||||||
|
- `primary_keyword`: CharField (optional)
|
||||||
|
- `secondary_keywords`: TextField (optional)
|
||||||
|
|
||||||
#### Images
|
#### Images
|
||||||
**File**: `modules/writer/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_images`
|
**Table**: `igny8_images`
|
||||||
|
|
||||||
**Fields**:
|
**Inherits**: `SiteSectorBaseModel`
|
||||||
- Inherits from `SiteSectorBaseModel`
|
|
||||||
- `task`: ForeignKey to Tasks
|
|
||||||
- `image_type`: CharField (choices: featured, desktop, mobile, in_article)
|
|
||||||
- `image_url`: URLField
|
|
||||||
- `image_path`: CharField (local path)
|
|
||||||
- `prompt`: TextField
|
|
||||||
- `status`: CharField
|
|
||||||
- `position`: IntegerField
|
|
||||||
|
|
||||||
**Methods**:
|
**Fields**:
|
||||||
- `save()`: Automatically sets account, site, sector from task
|
- `task`: ForeignKey to Tasks (optional)
|
||||||
|
- `content`: ForeignKey to Content (optional)
|
||||||
|
- `image_type`: CharField (choices: featured, in_article, desktop, mobile)
|
||||||
|
- `prompt`: TextField
|
||||||
|
- `image_url`: CharField
|
||||||
|
- `status`: CharField
|
||||||
|
|
||||||
### System Models
|
### System Models
|
||||||
|
|
||||||
#### AIPrompt
|
#### AIPrompt
|
||||||
**File**: `modules/system/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_ai_prompts`
|
**Table**: `igny8_ai_prompts`
|
||||||
|
|
||||||
**Fields**:
|
**Inherits**: `AccountBaseModel`
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `prompt_type`: CharField (choices: clustering, ideas, content_generation, image_prompt_extraction, image_prompt_template, negative_prompt)
|
|
||||||
- `prompt_value`: TextField
|
|
||||||
- `default_prompt`: TextField
|
|
||||||
- `is_active`: BooleanField
|
|
||||||
|
|
||||||
**Unique Constraint**: `(account, prompt_type)`
|
**Fields**:
|
||||||
|
- `prompt_type`: CharField
|
||||||
|
- `prompt_value`: TextField
|
||||||
|
- `function_name`: CharField (optional)
|
||||||
|
|
||||||
#### IntegrationSettings
|
#### IntegrationSettings
|
||||||
**File**: `modules/system/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_integration_settings`
|
**Table**: `igny8_integration_settings`
|
||||||
|
|
||||||
**Fields**:
|
**Inherits**: `AccountBaseModel`
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `integration_type`: CharField (choices: openai, runware, gsc, image_generation)
|
|
||||||
- `config`: JSONField (API keys, settings, etc.)
|
|
||||||
- `is_active`: BooleanField
|
|
||||||
|
|
||||||
**Unique Constraint**: `(account, integration_type)`
|
**Fields**:
|
||||||
|
- `integration_type`: CharField (choices: openai, runware, image_generation)
|
||||||
|
- `config`: JSONField
|
||||||
|
|
||||||
#### AuthorProfile
|
#### AuthorProfile
|
||||||
**File**: `modules/system/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_author_profiles`
|
**Table**: `igny8_author_profiles`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `name`: CharField
|
- `name`: CharField
|
||||||
- `description`: TextField
|
- `description`: TextField
|
||||||
- `tone`: CharField
|
- `tone`: CharField
|
||||||
- `language`: CharField
|
- `language`: CharField
|
||||||
- `structure_template`: JSONField
|
|
||||||
- `is_active`: BooleanField
|
|
||||||
|
|
||||||
#### Strategy
|
#### Strategy
|
||||||
**File**: `modules/system/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_strategies`
|
**Table**: `igny8_strategies`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
**Fields**:
|
**Fields**:
|
||||||
- Inherits from `AccountBaseModel`
|
|
||||||
- `name`: CharField
|
- `name`: CharField
|
||||||
- `description`: TextField
|
- `description`: TextField
|
||||||
- `sector`: ForeignKey to Sector (optional)
|
- `sector`: ForeignKey to Sector (optional)
|
||||||
@@ -406,6 +361,30 @@ backend/igny8_core/
|
|||||||
- `section_logic`: JSONField
|
- `section_logic`: JSONField
|
||||||
- `is_active`: BooleanField
|
- `is_active`: BooleanField
|
||||||
|
|
||||||
|
### Billing Models
|
||||||
|
|
||||||
|
#### CreditTransaction
|
||||||
|
**Table**: `igny8_credit_transactions`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
|
**Fields**:
|
||||||
|
- `transaction_type`: CharField (choices: purchase, usage, refund, adjustment)
|
||||||
|
- `amount`: IntegerField
|
||||||
|
- `balance_after`: IntegerField
|
||||||
|
- `description`: TextField (optional)
|
||||||
|
|
||||||
|
#### CreditUsageLog
|
||||||
|
**Table**: `igny8_credit_usage_logs`
|
||||||
|
|
||||||
|
**Inherits**: `AccountBaseModel`
|
||||||
|
|
||||||
|
**Fields**:
|
||||||
|
- `operation_type`: CharField
|
||||||
|
- `credits_used`: IntegerField
|
||||||
|
- `cost_usd`: DecimalField
|
||||||
|
- `details`: JSONField (optional)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ViewSets
|
## ViewSets
|
||||||
@@ -448,8 +427,6 @@ backend/igny8_core/
|
|||||||
### Planner ViewSets
|
### Planner ViewSets
|
||||||
|
|
||||||
#### KeywordViewSet
|
#### KeywordViewSet
|
||||||
**File**: `modules/planner/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `SiteSectorModelViewSet`
|
**Inherits**: `SiteSectorModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -471,8 +448,6 @@ backend/igny8_core/
|
|||||||
- Ordering: `created_at`, `volume`, `difficulty`
|
- Ordering: `created_at`, `volume`, `difficulty`
|
||||||
|
|
||||||
#### ClusterViewSet
|
#### ClusterViewSet
|
||||||
**File**: `modules/planner/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `SiteSectorModelViewSet`
|
**Inherits**: `SiteSectorModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -484,8 +459,6 @@ backend/igny8_core/
|
|||||||
- `auto_generate_ideas()`: Auto-generate content ideas for clusters
|
- `auto_generate_ideas()`: Auto-generate content ideas for clusters
|
||||||
|
|
||||||
#### ContentIdeasViewSet
|
#### ContentIdeasViewSet
|
||||||
**File**: `modules/planner/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `SiteSectorModelViewSet`
|
**Inherits**: `SiteSectorModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -498,8 +471,6 @@ backend/igny8_core/
|
|||||||
### Writer ViewSets
|
### Writer ViewSets
|
||||||
|
|
||||||
#### TasksViewSet
|
#### TasksViewSet
|
||||||
**File**: `modules/writer/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `SiteSectorModelViewSet`
|
**Inherits**: `SiteSectorModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -509,7 +480,7 @@ backend/igny8_core/
|
|||||||
- `update()`: Update task
|
- `update()`: Update task
|
||||||
- `destroy()`: Delete task
|
- `destroy()`: Delete task
|
||||||
- `auto_generate_content()`: Auto-generate content for tasks
|
- `auto_generate_content()`: Auto-generate content for tasks
|
||||||
- `auto_generate_images()`: Auto-generate images for tasks
|
- `generate_images()`: Generate images for image records
|
||||||
- `bulk_delete()`: Bulk delete tasks
|
- `bulk_delete()`: Bulk delete tasks
|
||||||
- `bulk_update()`: Bulk update task status
|
- `bulk_update()`: Bulk update task status
|
||||||
|
|
||||||
@@ -518,11 +489,20 @@ backend/igny8_core/
|
|||||||
- Filters: `status`, `cluster_id`, `content_type`, `content_structure`
|
- Filters: `status`, `cluster_id`, `content_type`, `content_structure`
|
||||||
- Ordering: `title`, `created_at`, `word_count`, `status`
|
- Ordering: `title`, `created_at`, `word_count`, `status`
|
||||||
|
|
||||||
|
#### ImagesViewSet
|
||||||
|
**Inherits**: `SiteSectorModelViewSet`
|
||||||
|
|
||||||
|
**Actions**:
|
||||||
|
- `list()`: List images
|
||||||
|
- `create()`: Create image
|
||||||
|
- `retrieve()`: Get image details
|
||||||
|
- `update()`: Update image
|
||||||
|
- `destroy()`: Delete image
|
||||||
|
- `generate_images()`: Generate images using AI
|
||||||
|
|
||||||
### System ViewSets
|
### System ViewSets
|
||||||
|
|
||||||
#### IntegrationSettingsViewSet
|
#### IntegrationSettingsViewSet
|
||||||
**File**: `modules/system/integration_views.py`
|
|
||||||
|
|
||||||
**Inherits**: `viewsets.ViewSet`
|
**Inherits**: `viewsets.ViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -537,8 +517,6 @@ backend/igny8_core/
|
|||||||
- `task_progress()`: Get Celery task progress
|
- `task_progress()`: Get Celery task progress
|
||||||
|
|
||||||
#### AIPromptViewSet
|
#### AIPromptViewSet
|
||||||
**File**: `modules/system/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `AccountModelViewSet`
|
**Inherits**: `AccountModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -550,8 +528,6 @@ backend/igny8_core/
|
|||||||
- `reset_to_default()`: Reset prompt to default value
|
- `reset_to_default()`: Reset prompt to default value
|
||||||
|
|
||||||
#### AuthorProfileViewSet
|
#### AuthorProfileViewSet
|
||||||
**File**: `modules/system/views.py`
|
|
||||||
|
|
||||||
**Inherits**: `AccountModelViewSet`
|
**Inherits**: `AccountModelViewSet`
|
||||||
|
|
||||||
**Actions**:
|
**Actions**:
|
||||||
@@ -568,63 +544,65 @@ backend/igny8_core/
|
|||||||
### Planner Serializers
|
### Planner Serializers
|
||||||
|
|
||||||
#### KeywordSerializer
|
#### KeywordSerializer
|
||||||
**File**: `modules/planner/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All Keyword model fields
|
**Fields**: All Keyword model fields
|
||||||
|
|
||||||
**Validation**: Validates keyword uniqueness, cluster belongs to same sector
|
**Validation**: Validates keyword uniqueness, cluster belongs to same sector
|
||||||
|
|
||||||
#### ClusterSerializer
|
#### ClusterSerializer
|
||||||
**File**: `modules/planner/cluster_serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All Cluster model fields
|
**Fields**: All Cluster model fields
|
||||||
|
|
||||||
**Read-Only Fields**: `keywords_count`, `volume` (calculated)
|
**Read-Only Fields**: `keywords_count`, `volume` (calculated)
|
||||||
|
|
||||||
#### ContentIdeasSerializer
|
#### ContentIdeasSerializer
|
||||||
**File**: `modules/planner/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All ContentIdeas model fields
|
**Fields**: All ContentIdeas model fields
|
||||||
|
|
||||||
### Writer Serializers
|
### Writer Serializers
|
||||||
|
|
||||||
#### TasksSerializer
|
#### TasksSerializer
|
||||||
**File**: `modules/writer/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All Tasks model fields
|
**Fields**: All Tasks model fields
|
||||||
|
|
||||||
#### ContentSerializer
|
#### ContentSerializer
|
||||||
**File**: `modules/writer/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All Content model fields
|
**Fields**: All Content model fields
|
||||||
|
|
||||||
#### ImagesSerializer
|
#### ImagesSerializer
|
||||||
**File**: `modules/writer/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All Images model fields
|
**Fields**: All Images model fields
|
||||||
|
|
||||||
### System Serializers
|
### System Serializers
|
||||||
|
|
||||||
#### AIPromptSerializer
|
#### AIPromptSerializer
|
||||||
**File**: `modules/system/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All AIPrompt model fields
|
**Fields**: All AIPrompt model fields
|
||||||
|
|
||||||
#### IntegrationSettingsSerializer
|
#### IntegrationSettingsSerializer
|
||||||
**File**: `modules/system/serializers.py`
|
|
||||||
|
|
||||||
**Fields**: All IntegrationSettings model fields
|
**Fields**: All IntegrationSettings model fields
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Celery Tasks
|
## Celery Tasks
|
||||||
|
|
||||||
|
### AI Task Entry Point
|
||||||
|
|
||||||
|
#### run_ai_task
|
||||||
|
**File**: `ai/tasks.py`
|
||||||
|
|
||||||
|
**Purpose**: Unified Celery task entrypoint for all AI functions
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `function_name`: Function name (e.g., 'auto_cluster')
|
||||||
|
- `payload`: Function-specific payload
|
||||||
|
- `account_id`: Account ID
|
||||||
|
|
||||||
|
**Flow**:
|
||||||
|
1. Gets account from account_id
|
||||||
|
2. Gets function instance from registry
|
||||||
|
3. Creates AIEngine
|
||||||
|
4. Executes function via AIEngine
|
||||||
|
|
||||||
### Planner Tasks
|
### Planner Tasks
|
||||||
|
|
||||||
#### auto_cluster_keywords_task
|
#### auto_cluster_keywords_task
|
||||||
**File**: `modules/planner/tasks.py`
|
**File**: `modules/planner/tasks.py` (legacy, now uses `run_ai_task`)
|
||||||
|
|
||||||
**Purpose**: Auto-cluster keywords using AI.
|
**Purpose**: Auto-cluster keywords using AI
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
- `keyword_ids`: List of keyword IDs
|
- `keyword_ids`: List of keyword IDs
|
||||||
@@ -634,12 +612,10 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**Progress Tracking**: Updates progress with request_steps and response_steps
|
**Progress Tracking**: Updates progress with request_steps and response_steps
|
||||||
|
|
||||||
**Calls**: `_auto_cluster_keywords_core()`
|
|
||||||
|
|
||||||
#### auto_generate_ideas_task
|
#### auto_generate_ideas_task
|
||||||
**File**: `modules/planner/tasks.py`
|
**File**: `modules/planner/tasks.py` (legacy, now uses `run_ai_task`)
|
||||||
|
|
||||||
**Purpose**: Auto-generate content ideas for clusters.
|
**Purpose**: Auto-generate content ideas for clusters
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
- `cluster_ids`: List of cluster IDs
|
- `cluster_ids`: List of cluster IDs
|
||||||
@@ -647,14 +623,12 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**Progress Tracking**: Updates progress for each cluster
|
**Progress Tracking**: Updates progress for each cluster
|
||||||
|
|
||||||
**Calls**: `_generate_single_idea_core()` for each cluster
|
|
||||||
|
|
||||||
### Writer Tasks
|
### Writer Tasks
|
||||||
|
|
||||||
#### auto_generate_content_task
|
#### auto_generate_content_task
|
||||||
**File**: `modules/writer/tasks.py`
|
**File**: `modules/writer/tasks.py` (legacy, now uses `run_ai_task`)
|
||||||
|
|
||||||
**Purpose**: Auto-generate content for tasks.
|
**Purpose**: Auto-generate content for tasks
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
- `task_ids`: List of task IDs
|
- `task_ids`: List of task IDs
|
||||||
@@ -662,20 +636,17 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**Progress Tracking**: Updates progress for each task
|
**Progress Tracking**: Updates progress for each task
|
||||||
|
|
||||||
**Calls**: `AIProcessor.generate_content()`
|
#### process_image_generation_queue
|
||||||
|
**File**: `modules/writer/views.py` (via `ai/tasks.py`)
|
||||||
|
|
||||||
#### auto_generate_images_task
|
**Purpose**: Generate images for image records
|
||||||
**File**: `modules/writer/tasks.py`
|
|
||||||
|
|
||||||
**Purpose**: Auto-generate images for tasks.
|
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
- `task_ids`: List of task IDs
|
- `image_ids`: List of image IDs
|
||||||
- `account_id`: Account ID
|
- `account_id`: Account ID
|
||||||
|
- `content_id`: Content ID (optional)
|
||||||
|
|
||||||
**Progress Tracking**: Updates progress for each task
|
**Progress Tracking**: Updates progress for each image sequentially
|
||||||
|
|
||||||
**Calls**: `AIProcessor.extract_image_prompts()` and `AIProcessor.generate_image()`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -705,7 +676,7 @@ backend/igny8_core/
|
|||||||
|
|
||||||
- `GET /api/v1/writer/tasks/` - List tasks
|
- `GET /api/v1/writer/tasks/` - List tasks
|
||||||
- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content
|
- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content
|
||||||
- `POST /api/v1/writer/tasks/auto_generate_images/` - Auto-generate images
|
- `POST /api/v1/writer/images/generate_images/` - Generate images
|
||||||
|
|
||||||
### System Endpoints
|
### System Endpoints
|
||||||
|
|
||||||
@@ -724,7 +695,7 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**File**: `api/base.py`
|
**File**: `api/base.py`
|
||||||
|
|
||||||
**Purpose**: Base ViewSet with automatic account filtering.
|
**Purpose**: Base ViewSet with automatic account filtering
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Automatic account filtering
|
- Automatic account filtering
|
||||||
@@ -735,7 +706,7 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**File**: `api/base.py`
|
**File**: `api/base.py`
|
||||||
|
|
||||||
**Purpose**: Base ViewSet with site/sector filtering.
|
**Purpose**: Base ViewSet with site/sector filtering
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Account filtering (inherited)
|
- Account filtering (inherited)
|
||||||
@@ -751,7 +722,7 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**File**: `middleware/account.py`
|
**File**: `middleware/account.py`
|
||||||
|
|
||||||
**Purpose**: Sets `request.account` from JWT token.
|
**Purpose**: Sets `request.account` from JWT token
|
||||||
|
|
||||||
**Functionality**:
|
**Functionality**:
|
||||||
- Extracts account ID from JWT token
|
- Extracts account ID from JWT token
|
||||||
@@ -762,7 +733,7 @@ backend/igny8_core/
|
|||||||
|
|
||||||
**File**: `middleware/resource_tracker.py`
|
**File**: `middleware/resource_tracker.py`
|
||||||
|
|
||||||
**Purpose**: Tracks API request metrics.
|
**Purpose**: Tracks API request metrics
|
||||||
|
|
||||||
**Functionality**:
|
**Functionality**:
|
||||||
- Tracks CPU, memory, I/O usage
|
- Tracks CPU, memory, I/O usage
|
||||||
@@ -773,29 +744,15 @@ backend/igny8_core/
|
|||||||
|
|
||||||
## Utilities
|
## Utilities
|
||||||
|
|
||||||
### AIProcessor
|
|
||||||
|
|
||||||
**File**: `utils/ai_processor.py`
|
|
||||||
|
|
||||||
**Purpose**: Unified AI interface for all AI operations.
|
|
||||||
|
|
||||||
**Methods**:
|
|
||||||
- `cluster_keywords()`: Cluster keywords using AI
|
|
||||||
- `generate_ideas()`: Generate content ideas
|
|
||||||
- `generate_content()`: Generate text content
|
|
||||||
- `extract_image_prompts()`: Extract image prompts from content
|
|
||||||
- `generate_image()`: Generate images using OpenAI DALL-E or Runware
|
|
||||||
|
|
||||||
**See**: AI Functions documentation for complete details
|
|
||||||
|
|
||||||
### Content Normalizer
|
### Content Normalizer
|
||||||
|
|
||||||
**File**: `utils/content_normalizer.py`
|
**File**: `utils/content_normalizer.py`
|
||||||
|
|
||||||
**Purpose**: Content processing utilities.
|
**Purpose**: Content processing utilities
|
||||||
|
|
||||||
**Functions**:
|
**Functions**:
|
||||||
- `_extract_body_content()`: Extract body content from HTML
|
- `normalize_content()`: Converts plain text to HTML
|
||||||
|
- `_extract_body_content()`: Extracts body content from HTML
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -803,58 +760,58 @@ backend/igny8_core/
|
|||||||
|
|
||||||
### Planner Module
|
### Planner Module
|
||||||
|
|
||||||
**Purpose**: Keyword management and content planning.
|
**Purpose**: Keyword management and content planning
|
||||||
|
|
||||||
**Models**: Keywords, Clusters, ContentIdeas
|
**Models**: Keywords, Clusters, ContentIdeas
|
||||||
|
|
||||||
**ViewSets**: KeywordViewSet, ClusterViewSet, ContentIdeasViewSet
|
**ViewSets**: KeywordViewSet, ClusterViewSet, ContentIdeasViewSet
|
||||||
|
|
||||||
**Tasks**: auto_cluster_keywords_task, auto_generate_ideas_task
|
**Tasks**: Auto-cluster keywords, Auto-generate ideas
|
||||||
|
|
||||||
### Writer Module
|
### Writer Module
|
||||||
|
|
||||||
**Purpose**: Content generation and management.
|
**Purpose**: Content generation and management
|
||||||
|
|
||||||
**Models**: Tasks, Content, Images
|
**Models**: Tasks, Content, Images
|
||||||
|
|
||||||
**ViewSets**: TasksViewSet
|
**ViewSets**: TasksViewSet, ImagesViewSet
|
||||||
|
|
||||||
**Tasks**: auto_generate_content_task, auto_generate_images_task
|
**Tasks**: Auto-generate content, Generate images
|
||||||
|
|
||||||
### System Module
|
### System Module
|
||||||
|
|
||||||
**Purpose**: System settings, prompts, and integrations.
|
**Purpose**: System configuration and AI settings
|
||||||
|
|
||||||
**Models**: AIPrompt, IntegrationSettings, AuthorProfile, Strategy
|
**Models**: AIPrompt, IntegrationSettings, AuthorProfile, Strategy
|
||||||
|
|
||||||
**ViewSets**: AIPromptViewSet, AuthorProfileViewSet, IntegrationSettingsViewSet
|
**ViewSets**: AIPromptViewSet, IntegrationSettingsViewSet, AuthorProfileViewSet
|
||||||
|
|
||||||
**Utilities**: Default prompts, prompt loading
|
|
||||||
|
|
||||||
### Billing Module
|
### Billing Module
|
||||||
|
|
||||||
**Purpose**: Credits, transactions, and usage tracking.
|
**Purpose**: Credit management and usage tracking
|
||||||
|
|
||||||
**Models**: CreditTransaction, UsageLog
|
**Models**: CreditTransaction, CreditUsageLog
|
||||||
|
|
||||||
**ViewSets**: CreditTransactionViewSet, UsageLogViewSet
|
**ViewSets**: CreditTransactionViewSet, CreditUsageLogViewSet
|
||||||
|
|
||||||
**Services**: CreditService
|
**Services**: CreditService (check, deduct, add, calculate credits)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
The IGNY8 backend is built on:
|
The IGNY8 backend provides:
|
||||||
|
|
||||||
1. **Django + DRF**: Robust web framework with RESTful API
|
1. **Multi-Tenancy**: Complete account isolation with automatic filtering
|
||||||
2. **Multi-Tenancy**: Complete account isolation with automatic filtering
|
2. **RESTful API**: DRF ViewSets with consistent response format
|
||||||
3. **Modular Architecture**: Clear module boundaries with shared utilities
|
3. **Celery Integration**: Asynchronous task processing
|
||||||
4. **Celery Integration**: Asynchronous task processing for long-running operations
|
4. **Hierarchical Organization**: Account > Site > Sector > Content structure
|
||||||
5. **Base ViewSets**: Consistent access control and filtering
|
5. **AI Framework**: Unified AI framework for all AI operations
|
||||||
6. **AI Integration**: Unified AIProcessor for all AI operations
|
6. **Progress Tracking**: Real-time progress updates for Celery tasks
|
||||||
7. **Progress Tracking**: Real-time progress updates for Celery tasks
|
7. **Module-Based Design**: Clear separation of concerns
|
||||||
8. **Account/Site/Sector Hierarchy**: Hierarchical data organization
|
8. **Base Classes**: Reusable ViewSets for common patterns
|
||||||
|
9. **Middleware**: Account context and resource tracking
|
||||||
|
10. **Utilities**: Content processing and AI integration
|
||||||
|
|
||||||
This architecture ensures scalability, maintainability, and extensibility while providing a robust API for the frontend.
|
This architecture ensures scalability, maintainability, and extensibility while providing a robust foundation for the IGNY8 platform.
|
||||||
|
|
||||||
@@ -1,739 +0,0 @@
|
|||||||
# IGNY8 Account, User, Plan, Sites, Credits Documentation
|
|
||||||
|
|
||||||
**Version:** 1.0
|
|
||||||
**Last Updated:** 2025-01-XX
|
|
||||||
**Purpose:** Complete documentation of multi-tenancy architecture, access control, plans, credits, and related systems.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Overview](#overview)
|
|
||||||
2. [Account Model](#account-model)
|
|
||||||
3. [User Model](#user-model)
|
|
||||||
4. [Plan Model](#plan-model)
|
|
||||||
5. [Subscription Model](#subscription-model)
|
|
||||||
6. [Site Model](#site-model)
|
|
||||||
7. [Sector Model](#sector-model)
|
|
||||||
8. [Industry & IndustrySector Models](#industry--industrysector-models)
|
|
||||||
9. [Access Control](#access-control)
|
|
||||||
10. [Credits System](#credits-system)
|
|
||||||
11. [Plan Limits](#plan-limits)
|
|
||||||
12. [Multi-Tenancy Architecture](#multi-tenancy-architecture)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The IGNY8 platform uses a multi-account architecture with the following core entities:
|
|
||||||
|
|
||||||
- **Account**: Top-level organization/workspace
|
|
||||||
- **User**: Individual user accounts with roles
|
|
||||||
- **Plan**: Subscription plan templates with limits
|
|
||||||
- **Subscription**: Active subscription linking Account to Plan
|
|
||||||
- **Site**: Workspace within an Account (1-N relationship)
|
|
||||||
- **Sector**: Content category within a Site (1-5 per site)
|
|
||||||
- **Industry**: Global industry templates
|
|
||||||
- **IndustrySector**: Industry sector templates
|
|
||||||
|
|
||||||
### Key Relationships
|
|
||||||
|
|
||||||
```
|
|
||||||
Account (1) ──< (N) User
|
|
||||||
Account (1) ──< (1) Subscription ──> (1) Plan
|
|
||||||
Account (1) ──< (N) Site
|
|
||||||
Site (1) ──< (1-5) Sector
|
|
||||||
Industry (1) ──< (N) IndustrySector
|
|
||||||
Site (1) ──> (1) Industry (optional)
|
|
||||||
Sector (1) ──> (1) IndustrySector (optional, template reference)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Account Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_accounts`
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `name`: CharField - Account name
|
|
||||||
- `slug`: SlugField - Unique slug identifier
|
|
||||||
- `owner`: ForeignKey to User - Account owner
|
|
||||||
- `stripe_customer_id`: CharField - Stripe customer ID (optional)
|
|
||||||
- `plan`: ForeignKey to Plan - Current subscription plan
|
|
||||||
- `credits`: IntegerField - Current credit balance (default: 0)
|
|
||||||
- `status`: CharField - Account status (choices: active, suspended, trial, cancelled)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Status Values
|
|
||||||
|
|
||||||
- `active`: Normal operation
|
|
||||||
- `suspended`: Access temporarily revoked
|
|
||||||
- `trial`: Limited trial access
|
|
||||||
- `cancelled`: Account terminated
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### is_system_account()
|
|
||||||
**Returns**: `True` if account is a system account (aws-admin, default-account, default)
|
|
||||||
|
|
||||||
**Purpose**: System accounts bypass all filtering restrictions
|
|
||||||
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **One-to-Many**: Users (via `user.account`)
|
|
||||||
- **One-to-One**: Subscription (via `account.subscription`)
|
|
||||||
- **One-to-Many**: Sites (via `site.account`)
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## User Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_users`
|
|
||||||
|
|
||||||
**Inherits**: `AbstractUser` (Django's built-in user model)
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key (inherited from AbstractUser)
|
|
||||||
- `email`: EmailField - Unique, USERNAME_FIELD
|
|
||||||
- `username`: CharField - Username
|
|
||||||
- `password`: Hashed password (inherited)
|
|
||||||
- `account`: ForeignKey to Account - User's account (null=True, blank=True)
|
|
||||||
- `role`: CharField - User role (choices: developer, owner, admin, editor, viewer, system_bot)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Role Hierarchy (from highest to lowest)
|
|
||||||
|
|
||||||
1. **developer**: Full system access, bypasses all restrictions
|
|
||||||
2. **owner**: Full access to account, can manage users and billing
|
|
||||||
3. **admin**: Admin access to account, can manage content and users
|
|
||||||
4. **editor**: Can edit content, manage clusters/tasks
|
|
||||||
5. **viewer**: Read-only access
|
|
||||||
6. **system_bot**: System automation user
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### has_role(*roles)
|
|
||||||
**Parameters**: `*roles` - Variable number of role strings
|
|
||||||
|
|
||||||
**Returns**: `True` if user has any of the specified roles
|
|
||||||
|
|
||||||
#### is_owner_or_admin()
|
|
||||||
**Returns**: `True` if role is owner or admin
|
|
||||||
|
|
||||||
#### is_developer()
|
|
||||||
**Returns**: `True` if role is developer or is_superuser
|
|
||||||
|
|
||||||
#### is_admin_or_developer()
|
|
||||||
**Returns**: `True` if role is admin or developer (bypasses restrictions)
|
|
||||||
|
|
||||||
**Purpose**: Admin/Developer users bypass account/site/sector filtering
|
|
||||||
|
|
||||||
#### is_system_account_user()
|
|
||||||
**Returns**: `True` if user belongs to system account
|
|
||||||
|
|
||||||
**Purpose**: System account users bypass all filtering restrictions
|
|
||||||
|
|
||||||
#### get_accessible_sites()
|
|
||||||
**Returns**: QuerySet of sites user can access
|
|
||||||
|
|
||||||
**Access Control Logic**:
|
|
||||||
- **System Account Users**: All active sites across all accounts
|
|
||||||
- **Developers**: All active sites across all accounts
|
|
||||||
- **Owners/Admins**: All sites in their account
|
|
||||||
- **Editors/Viewers**: Only sites explicitly granted via `SiteUserAccess`
|
|
||||||
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **Many-to-One**: Account (via `user.account`)
|
|
||||||
- **Many-to-Many**: Sites (via `SiteUserAccess`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Plan Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_plans`
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
#### Plan Information
|
|
||||||
- `id`: Primary key
|
|
||||||
- `name`: CharField - Plan name (e.g., "Free", "Starter", "Growth")
|
|
||||||
- `slug`: SlugField - Unique slug identifier
|
|
||||||
- `price`: DecimalField - Monthly price
|
|
||||||
- `billing_cycle`: CharField - Billing cycle (choices: monthly, annual)
|
|
||||||
- `features`: JSONField - Array of feature strings (e.g., ['ai_writer', 'image_gen', 'auto_publish'])
|
|
||||||
- `is_active`: BooleanField - Whether plan is available for subscription
|
|
||||||
|
|
||||||
#### User/Site/Scope Limits
|
|
||||||
- `max_users`: IntegerField - Total users allowed per account (default: 1, min: 1)
|
|
||||||
- `max_sites`: IntegerField - Maximum sites allowed (default: 1, min: 1)
|
|
||||||
- `max_industries`: IntegerField - Optional limit for industries/sectors (nullable)
|
|
||||||
- `max_author_profiles`: IntegerField - Limit for saved writing styles (default: 5)
|
|
||||||
|
|
||||||
#### Planner Limits
|
|
||||||
- `max_keywords`: IntegerField - Total keywords allowed globally (default: 1000)
|
|
||||||
- `max_clusters`: IntegerField - Total clusters allowed globally (default: 100)
|
|
||||||
- `max_content_ideas`: IntegerField - Total content ideas allowed globally (default: 300)
|
|
||||||
- `daily_cluster_limit`: IntegerField - Max clusters per day (default: 10)
|
|
||||||
- `daily_keyword_import_limit`: IntegerField - Seed keywords import limit per day (default: 100)
|
|
||||||
- `monthly_cluster_ai_credits`: IntegerField - AI credits for clustering (default: 50)
|
|
||||||
|
|
||||||
#### Writer Limits
|
|
||||||
- `daily_content_tasks`: IntegerField - Max content tasks per day (default: 10)
|
|
||||||
- `daily_ai_requests`: IntegerField - Total AI executions per day (default: 50)
|
|
||||||
- `monthly_word_count_limit`: IntegerField - Monthly word limit for generated content (default: 50000)
|
|
||||||
- `monthly_content_ai_credits`: IntegerField - AI credit pool for content generation (default: 200)
|
|
||||||
|
|
||||||
#### Image Generation Limits
|
|
||||||
- `monthly_image_count`: IntegerField - Max images per month (default: 100)
|
|
||||||
- `daily_image_generation_limit`: IntegerField - Max images per day (default: 25)
|
|
||||||
- `monthly_image_ai_credits`: IntegerField - AI credit pool for images (default: 100)
|
|
||||||
- `max_images_per_task`: IntegerField - Max images per content task (default: 4, min: 1)
|
|
||||||
- `image_model_choices`: JSONField - Allowed image models (e.g., ['dalle3', 'hidream'])
|
|
||||||
|
|
||||||
#### AI Request Controls
|
|
||||||
- `daily_ai_request_limit`: IntegerField - Global daily AI request cap (default: 100)
|
|
||||||
- `monthly_ai_credit_limit`: IntegerField - Unified credit ceiling per month (default: 500)
|
|
||||||
|
|
||||||
#### Billing & Credits
|
|
||||||
- `included_credits`: IntegerField - Monthly credits included (default: 0)
|
|
||||||
- `extra_credit_price`: DecimalField - Price per additional credit (default: 0.01)
|
|
||||||
- `allow_credit_topup`: BooleanField - Can user purchase more credits? (default: True)
|
|
||||||
- `auto_credit_topup_threshold`: IntegerField - Auto top-up trigger point (nullable)
|
|
||||||
- `auto_credit_topup_amount`: IntegerField - Credits to auto-buy (nullable)
|
|
||||||
|
|
||||||
#### Stripe Integration
|
|
||||||
- `stripe_product_id`: CharField - Stripe product ID (nullable)
|
|
||||||
- `stripe_price_id`: CharField - Stripe price ID (nullable)
|
|
||||||
|
|
||||||
#### Legacy Fields
|
|
||||||
- `credits_per_month`: IntegerField - DEPRECATED: Use included_credits instead (default: 0)
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### clean()
|
|
||||||
**Purpose**: Validates plan limits
|
|
||||||
|
|
||||||
**Validations**:
|
|
||||||
- `max_sites` must be >= 1
|
|
||||||
- `included_credits` must be >= 0
|
|
||||||
|
|
||||||
#### get_effective_credits_per_month()
|
|
||||||
**Returns**: `included_credits` if set, otherwise `credits_per_month` (backward compatibility)
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **One-to-Many**: Accounts (via `account.plan`)
|
|
||||||
|
|
||||||
### Plan Limits Enforcement
|
|
||||||
|
|
||||||
**Current Status**: Plan limits are defined but **not currently enforced** in AI functions.
|
|
||||||
|
|
||||||
**Future Implementation**: Plan limits should be checked before allowing operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Subscription Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_subscriptions`
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `account`: OneToOneField to Account - Account subscription
|
|
||||||
- `stripe_subscription_id`: CharField - Unique Stripe subscription ID
|
|
||||||
- `status`: CharField - Subscription status (choices: active, past_due, canceled, trialing)
|
|
||||||
- `current_period_start`: DateTimeField - Current billing period start
|
|
||||||
- `current_period_end`: DateTimeField - Current billing period end
|
|
||||||
- `cancel_at_period_end`: BooleanField - Cancel at period end flag (default: False)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Status Values
|
|
||||||
|
|
||||||
- `active`: Subscription is active and paid
|
|
||||||
- `past_due`: Payment failed, subscription past due
|
|
||||||
- `canceled`: Subscription canceled
|
|
||||||
- `trialing`: In trial period
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **One-to-One**: Account (via `account.subscription`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Site Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_sites`
|
|
||||||
|
|
||||||
**Inherits**: `AccountBaseModel`
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `account`: ForeignKey to Account - Account this site belongs to
|
|
||||||
- `name`: CharField - Site name
|
|
||||||
- `slug`: SlugField - Unique slug per account
|
|
||||||
- `domain`: URLField - Primary domain URL (optional)
|
|
||||||
- `description`: TextField - Site description (optional)
|
|
||||||
- `industry`: ForeignKey to Industry - Industry this site belongs to (optional)
|
|
||||||
- `is_active`: BooleanField - Whether site is active (default: True)
|
|
||||||
- `status`: CharField - Site status (choices: active, inactive, suspended, default: active)
|
|
||||||
- `wp_url`: URLField - WordPress site URL (optional, for WordPress integration)
|
|
||||||
- `wp_username`: CharField - WordPress username (optional)
|
|
||||||
- `wp_app_password`: CharField - WordPress app password (optional)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Unique Constraint
|
|
||||||
|
|
||||||
- `(account, slug)` - Slug unique per account
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### get_active_sectors_count()
|
|
||||||
**Returns**: Count of active sectors for this site
|
|
||||||
|
|
||||||
#### can_add_sector()
|
|
||||||
**Returns**: `True` if site can add another sector (max 5 sectors per site)
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **Many-to-One**: Account (via `site.account`)
|
|
||||||
- **Many-to-One**: Industry (via `site.industry`, optional)
|
|
||||||
- **One-to-Many**: Sectors (via `sector.site`)
|
|
||||||
- **Many-to-Many**: Users (via `SiteUserAccess`)
|
|
||||||
|
|
||||||
### Site Activation
|
|
||||||
|
|
||||||
**Important**: Multiple sites can be active simultaneously. The previous restriction of "only 1 site can be active at one time" has been removed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Sector Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_sectors`
|
|
||||||
|
|
||||||
**Inherits**: `AccountBaseModel`
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `account`: ForeignKey to Account - Account this sector belongs to
|
|
||||||
- `site`: ForeignKey to Site - Site this sector belongs to
|
|
||||||
- `industry_sector`: ForeignKey to IndustrySector - Reference to industry sector template (optional)
|
|
||||||
- `name`: CharField - Sector name
|
|
||||||
- `slug`: SlugField - Unique slug per site
|
|
||||||
- `description`: TextField - Sector description (optional)
|
|
||||||
- `is_active`: BooleanField - Whether sector is active (default: True)
|
|
||||||
- `status`: CharField - Sector status (choices: active, inactive, default: active)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Unique Constraint
|
|
||||||
|
|
||||||
- `(site, slug)` - Slug unique per site
|
|
||||||
|
|
||||||
### Validation
|
|
||||||
|
|
||||||
**On Save**:
|
|
||||||
1. Automatically sets `account` from `site.account`
|
|
||||||
2. Validates that `industry_sector.industry` matches `site.industry` (if both set)
|
|
||||||
3. Validates sector limit: Maximum 5 active sectors per site
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### industry (property)
|
|
||||||
**Returns**: Industry for this sector (from `industry_sector.industry` if set)
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **Many-to-One**: Account (via `sector.account`)
|
|
||||||
- **Many-to-One**: Site (via `sector.site`)
|
|
||||||
- **Many-to-One**: IndustrySector (via `sector.industry_sector`, optional, template reference)
|
|
||||||
- **One-to-Many**: Keywords, Clusters, ContentIdeas, Tasks (via their `sector` field)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Industry & IndustrySector Models
|
|
||||||
|
|
||||||
### Industry Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_industries`
|
|
||||||
|
|
||||||
**Purpose**: Global industry templates.
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `name`: CharField - Industry name (unique)
|
|
||||||
- `slug`: SlugField - Unique slug identifier
|
|
||||||
- `description`: TextField - Industry description (optional)
|
|
||||||
- `is_active`: BooleanField - Whether industry is active (default: True)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **One-to-Many**: Sites (via `site.industry`)
|
|
||||||
- **One-to-Many**: IndustrySectors (via `industry_sector.industry`)
|
|
||||||
|
|
||||||
### IndustrySector Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_industry_sectors`
|
|
||||||
|
|
||||||
**Purpose**: Sector templates within industries.
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `industry`: ForeignKey to Industry - Industry this sector belongs to
|
|
||||||
- `name`: CharField - Sector name
|
|
||||||
- `slug`: SlugField - Unique slug per industry
|
|
||||||
- `description`: TextField - Sector description (optional)
|
|
||||||
- `suggested_keywords`: JSONField - List of suggested keywords for this sector template
|
|
||||||
- `is_active`: BooleanField - Whether sector is active (default: True)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
- `updated_at`: DateTimeField - Last update timestamp
|
|
||||||
|
|
||||||
### Unique Constraint
|
|
||||||
|
|
||||||
- `(industry, slug)` - Slug unique per industry
|
|
||||||
|
|
||||||
### Relationships
|
|
||||||
|
|
||||||
- **Many-to-One**: Industry (via `industry_sector.industry`)
|
|
||||||
- **One-to-Many**: Sectors (via `sector.industry_sector`, template reference)
|
|
||||||
- **One-to-Many**: SeedKeywords (via `seed_keyword.sector`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Access Control
|
|
||||||
|
|
||||||
### Account Isolation
|
|
||||||
|
|
||||||
**Principle**: All data is isolated by account.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- All models inherit `AccountBaseModel` (has `account` ForeignKey)
|
|
||||||
- All ViewSets inherit `AccountModelViewSet` (filters by `request.account`)
|
|
||||||
- Middleware sets `request.account` from JWT token
|
|
||||||
|
|
||||||
**Access Control**:
|
|
||||||
- **Admin/Developer users**: Bypass account filtering (see all accounts)
|
|
||||||
- **System account users**: Bypass account filtering (see all accounts)
|
|
||||||
- **Regular users**: Only see data from their account
|
|
||||||
|
|
||||||
### Site Access Control
|
|
||||||
|
|
||||||
**Principle**: Users can only access sites they have permission to access.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- `User.get_accessible_sites()` returns sites user can access
|
|
||||||
- ViewSets filter by accessible sites
|
|
||||||
- `SiteUserAccess` model controls explicit site access for editors/viewers
|
|
||||||
|
|
||||||
**Access Levels**:
|
|
||||||
- **System Account Users**: All active sites across all accounts
|
|
||||||
- **Developers**: All active sites across all accounts
|
|
||||||
- **Owners/Admins**: All sites in their account
|
|
||||||
- **Editors/Viewers**: Only sites explicitly granted via `SiteUserAccess`
|
|
||||||
|
|
||||||
### SiteUserAccess Model
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/auth/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_site_user_access`
|
|
||||||
|
|
||||||
**Purpose**: Many-to-many relationship between Users and Sites for explicit access control.
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `user`: ForeignKey to User
|
|
||||||
- `site`: ForeignKey to Site
|
|
||||||
- `granted_at`: DateTimeField - When access was granted
|
|
||||||
- `granted_by`: ForeignKey to User - Who granted access (optional)
|
|
||||||
|
|
||||||
### Unique Constraint
|
|
||||||
|
|
||||||
- `(user, site)` - One access record per user-site pair
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
- Owners and Admins have automatic access to all sites in their account
|
|
||||||
- Editors and Viewers require explicit `SiteUserAccess` records
|
|
||||||
- System account users and Developers bypass this check
|
|
||||||
|
|
||||||
### Role-Based Access Control (RBAC)
|
|
||||||
|
|
||||||
**Role Hierarchy**:
|
|
||||||
1. **developer**: Full system access, bypasses all restrictions
|
|
||||||
2. **owner**: Full account access, can manage users and billing
|
|
||||||
3. **admin**: Account admin access, can manage content and users
|
|
||||||
4. **editor**: Content editing access, can manage clusters/tasks
|
|
||||||
5. **viewer**: Read-only access
|
|
||||||
|
|
||||||
**Permission Checks**:
|
|
||||||
- `user.has_role(*roles)`: Check if user has any of the specified roles
|
|
||||||
- `user.is_owner_or_admin()`: Check if user is owner or admin
|
|
||||||
- `user.is_developer()`: Check if user is developer
|
|
||||||
- `user.is_admin_or_developer()`: Check if user is admin or developer (bypasses restrictions)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Credits System
|
|
||||||
|
|
||||||
### Account Credits
|
|
||||||
|
|
||||||
**Field**: `Account.credits` (IntegerField, default: 0)
|
|
||||||
|
|
||||||
**Purpose**: Current credit balance for the account.
|
|
||||||
|
|
||||||
**Usage**: Credits are deducted for AI operations and added through purchases or subscriptions.
|
|
||||||
|
|
||||||
### Credit Models
|
|
||||||
|
|
||||||
#### CreditTransaction
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/modules/billing/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_credit_transactions`
|
|
||||||
|
|
||||||
**Purpose**: Track all credit transactions (additions, deductions).
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `account`: ForeignKey to Account
|
|
||||||
- `transaction_type`: CharField - Type of transaction (choices: purchase, subscription, refund, deduction, adjustment)
|
|
||||||
- `amount`: IntegerField - Positive for additions, negative for deductions
|
|
||||||
- `balance_after`: IntegerField - Credit balance after this transaction
|
|
||||||
- `description`: CharField - Transaction description
|
|
||||||
- `metadata`: JSONField - Additional context (AI call details, etc.)
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
|
|
||||||
#### CreditUsageLog
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/modules/billing/models.py`
|
|
||||||
|
|
||||||
**Table**: `igny8_credit_usage_logs`
|
|
||||||
|
|
||||||
**Purpose**: Detailed log of credit usage per AI operation.
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
- `id`: Primary key
|
|
||||||
- `account`: ForeignKey to Account
|
|
||||||
- `operation_type`: CharField - Type of operation (choices: clustering, ideas, content, images, reparse)
|
|
||||||
- `credits_used`: IntegerField - Number of credits used
|
|
||||||
- `cost_usd`: DecimalField - Cost in USD (optional)
|
|
||||||
- `model_used`: CharField - AI model used (optional)
|
|
||||||
- `tokens_input`: IntegerField - Input tokens (optional)
|
|
||||||
- `tokens_output`: IntegerField - Output tokens (optional)
|
|
||||||
- `related_object_type`: CharField - Related object type (optional)
|
|
||||||
- `related_object_id`: IntegerField - Related object ID (optional)
|
|
||||||
- `metadata`: JSONField - Additional metadata
|
|
||||||
- `created_at`: DateTimeField - Creation timestamp
|
|
||||||
|
|
||||||
### CreditService
|
|
||||||
|
|
||||||
**File**: `backend/igny8_core/modules/billing/services.py`
|
|
||||||
|
|
||||||
**Purpose**: Service for managing credits.
|
|
||||||
|
|
||||||
#### Methods
|
|
||||||
|
|
||||||
##### check_credits(account, required_credits)
|
|
||||||
**Purpose**: Check if account has enough credits.
|
|
||||||
|
|
||||||
**Raises**: `InsufficientCreditsError` if account doesn't have enough credits
|
|
||||||
|
|
||||||
##### deduct_credits(account, amount, operation_type, description, ...)
|
|
||||||
**Purpose**: Deduct credits and log transaction.
|
|
||||||
|
|
||||||
**Parameters**:
|
|
||||||
- `account`: Account instance
|
|
||||||
- `amount`: Number of credits to deduct
|
|
||||||
- `operation_type`: Type of operation
|
|
||||||
- `description`: Description of the transaction
|
|
||||||
- `metadata`: Optional metadata dict
|
|
||||||
- `cost_usd`: Optional cost in USD
|
|
||||||
- `model_used`: Optional AI model used
|
|
||||||
- `tokens_input`: Optional input tokens
|
|
||||||
- `tokens_output`: Optional output tokens
|
|
||||||
- `related_object_type`: Optional related object type
|
|
||||||
- `related_object_id`: Optional related object ID
|
|
||||||
|
|
||||||
**Returns**: New credit balance
|
|
||||||
|
|
||||||
**Creates**:
|
|
||||||
- `CreditTransaction` record
|
|
||||||
- `CreditUsageLog` record
|
|
||||||
|
|
||||||
##### add_credits(account, amount, transaction_type, description, ...)
|
|
||||||
**Purpose**: Add credits (purchase, subscription, etc.).
|
|
||||||
|
|
||||||
**Parameters**:
|
|
||||||
- `account`: Account instance
|
|
||||||
- `amount`: Number of credits to add
|
|
||||||
- `transaction_type`: Type of transaction
|
|
||||||
- `description`: Description of the transaction
|
|
||||||
- `metadata`: Optional metadata dict
|
|
||||||
|
|
||||||
**Returns**: New credit balance
|
|
||||||
|
|
||||||
**Creates**: `CreditTransaction` record
|
|
||||||
|
|
||||||
##### calculate_credits_for_operation(operation_type, **kwargs)
|
|
||||||
**Purpose**: Calculate credits needed for an operation.
|
|
||||||
|
|
||||||
**Parameters**:
|
|
||||||
- `operation_type`: Type of operation
|
|
||||||
- `**kwargs`: Operation-specific parameters
|
|
||||||
|
|
||||||
**Returns**: Number of credits required
|
|
||||||
|
|
||||||
**Raises**: `CreditCalculationError` if calculation fails
|
|
||||||
|
|
||||||
**Credit Costs**:
|
|
||||||
- `clustering`: 1 credit per 30 keywords
|
|
||||||
- `ideas`: 1 credit per idea
|
|
||||||
- `content`: 3 credits per content piece
|
|
||||||
- `images`: 1 credit per image
|
|
||||||
- `reparse`: 1 credit per reparse
|
|
||||||
|
|
||||||
### Credit Integration
|
|
||||||
|
|
||||||
**Current Status**: Credits system is implemented but **not currently enforced** in AI functions.
|
|
||||||
|
|
||||||
**Future Implementation**: Credits should be checked and deducted before allowing AI operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Plan Limits
|
|
||||||
|
|
||||||
### Planner Limits
|
|
||||||
|
|
||||||
- `max_keywords`: Total keywords allowed (not enforced)
|
|
||||||
- `max_clusters`: Total clusters allowed (not enforced)
|
|
||||||
- `max_content_ideas`: Total content ideas allowed (not enforced)
|
|
||||||
- `daily_cluster_limit`: Max clusters per day (not enforced)
|
|
||||||
- `monthly_cluster_ai_credits`: AI credits for clustering (not enforced)
|
|
||||||
|
|
||||||
### Writer Limits
|
|
||||||
|
|
||||||
- `daily_content_tasks`: Max content tasks per day (not enforced)
|
|
||||||
- `daily_ai_requests`: Total AI executions per day (not enforced)
|
|
||||||
- `monthly_word_count_limit`: Monthly word limit (not enforced)
|
|
||||||
- `monthly_content_ai_credits`: AI credits for content (not enforced)
|
|
||||||
|
|
||||||
### Image Limits
|
|
||||||
|
|
||||||
- `monthly_image_count`: Max images per month (not enforced)
|
|
||||||
- `daily_image_generation_limit`: Max images per day (not enforced)
|
|
||||||
- `monthly_image_ai_credits`: AI credits for images (not enforced)
|
|
||||||
- `max_images_per_task`: Max images per task (not enforced)
|
|
||||||
- `image_model_choices`: Allowed image models (not enforced)
|
|
||||||
|
|
||||||
### Feature Flags
|
|
||||||
|
|
||||||
- `features`: JSON array of enabled features (e.g., `['ai_writer', 'image_gen', 'auto_publish']`)
|
|
||||||
- **Not enforced**: Feature flags are not checked before allowing AI operations
|
|
||||||
|
|
||||||
### Plan Limits Enforcement
|
|
||||||
|
|
||||||
**Current Status**: Plan limits are defined but **not currently enforced** in AI functions.
|
|
||||||
|
|
||||||
**Future Implementation**: Plan limits should be checked before allowing operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Multi-Tenancy Architecture
|
|
||||||
|
|
||||||
### Account Isolation
|
|
||||||
|
|
||||||
**Principle**: All data is isolated by account.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
1. **Model Level**: All models inherit `AccountBaseModel` (has `account` ForeignKey)
|
|
||||||
2. **ViewSet Level**: All ViewSets inherit `AccountModelViewSet` (filters by `request.account`)
|
|
||||||
3. **Middleware Level**: `AccountContextMiddleware` sets `request.account` from JWT token
|
|
||||||
|
|
||||||
**Access Control**:
|
|
||||||
- Admin/Developer users: Bypass account filtering (see all accounts)
|
|
||||||
- System account users: Bypass account filtering (see all accounts)
|
|
||||||
- Regular users: Only see data from their account
|
|
||||||
|
|
||||||
### Site/Sector Hierarchy
|
|
||||||
|
|
||||||
**Structure**:
|
|
||||||
```
|
|
||||||
Account (1) ──< (N) Site
|
|
||||||
Site (1) ──< (1-5) Sector
|
|
||||||
Sector (1) ──< (N) Keywords, Clusters, ContentIdeas, Tasks
|
|
||||||
```
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Models inherit `SiteSectorBaseModel` (has `site` and `sector` ForeignKeys)
|
|
||||||
- ViewSets inherit `SiteSectorModelViewSet` (filters by accessible sites)
|
|
||||||
- User access control via `User.get_accessible_sites()`
|
|
||||||
|
|
||||||
**Site Access Control**:
|
|
||||||
- System account users: All active sites
|
|
||||||
- Developers: All active sites
|
|
||||||
- Owners/Admins: All sites in their account
|
|
||||||
- Editors/Viewers: Only sites granted via `SiteUserAccess`
|
|
||||||
|
|
||||||
### Data Isolation Flow
|
|
||||||
|
|
||||||
1. **Request Arrives**: JWT token contains account ID
|
|
||||||
2. **Middleware**: `AccountContextMiddleware` extracts account ID and sets `request.account`
|
|
||||||
3. **ViewSet**: `AccountModelViewSet.get_queryset()` filters by `request.account`
|
|
||||||
4. **Database**: All queries automatically filtered by account
|
|
||||||
|
|
||||||
**Override**: Admin/Developer users bypass account filtering
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
The IGNY8 multi-tenancy architecture provides:
|
|
||||||
|
|
||||||
1. **Complete Account Isolation**: All data isolated by account with automatic filtering
|
|
||||||
2. **Site/Sector Hierarchy**: Hierarchical organization with access control
|
|
||||||
3. **Role-Based Access Control**: Granular permissions based on user roles
|
|
||||||
4. **Plan-Based Limits**: Comprehensive plan limits (defined but not enforced)
|
|
||||||
5. **Credits System**: Credit tracking and deduction system (implemented but not enforced)
|
|
||||||
6. **Flexible Site Access**: Multiple sites can be active simultaneously
|
|
||||||
7. **Industry Templates**: Global industry and sector templates
|
|
||||||
|
|
||||||
This architecture ensures data security, scalability, and flexibility while providing a solid foundation for subscription management and billing.
|
|
||||||
|
|
||||||
494
docs/05-AI-FUNCTIONS.md
Normal file
494
docs/05-AI-FUNCTIONS.md
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
# IGNY8 AI Functions Documentation
|
||||||
|
|
||||||
|
**Last Updated:** 2025-01-XX
|
||||||
|
**Purpose:** Complete AI functions documentation covering architecture, all 5 AI functions, execution flow, and configuration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [AI Framework Overview](#ai-framework-overview)
|
||||||
|
2. [Common Architecture](#common-architecture)
|
||||||
|
3. [AI Function Execution Flow](#ai-function-execution-flow)
|
||||||
|
4. [AI Functions](#ai-functions)
|
||||||
|
5. [Progress Tracking](#progress-tracking)
|
||||||
|
6. [Cost Tracking](#cost-tracking)
|
||||||
|
7. [Prompt Management](#prompt-management)
|
||||||
|
8. [Model Configuration](#model-configuration)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Framework Overview
|
||||||
|
|
||||||
|
The IGNY8 AI framework provides a unified interface for all AI operations. All AI functions inherit from `BaseAIFunction` and are orchestrated by `AIEngine`, ensuring consistent execution, progress tracking, error handling, and cost tracking.
|
||||||
|
|
||||||
|
### Key Components
|
||||||
|
|
||||||
|
- **BaseAIFunction**: Abstract base class for all AI functions
|
||||||
|
- **AIEngine**: Central orchestrator managing lifecycle, progress, logging, cost tracking
|
||||||
|
- **AICore**: Centralized AI request handler for all AI operations
|
||||||
|
- **PromptRegistry**: Centralized prompt management with hierarchical resolution
|
||||||
|
- **Function Registry**: Lazy-loaded function registry
|
||||||
|
- **Progress Tracking**: Real-time progress updates via Celery
|
||||||
|
- **Cost Tracking**: Automatic cost and token tracking
|
||||||
|
|
||||||
|
### AI Functions
|
||||||
|
|
||||||
|
1. **Auto Cluster Keywords**: Group related keywords into semantic clusters
|
||||||
|
2. **Generate Ideas**: Generate content ideas from keyword clusters
|
||||||
|
3. **Generate Content**: Generate blog post and article content
|
||||||
|
4. **Generate Image Prompts**: Extract image prompts from content
|
||||||
|
5. **Generate Images**: Generate images using OpenAI DALL-E or Runware
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Architecture
|
||||||
|
|
||||||
|
### Core Framework Files
|
||||||
|
|
||||||
|
#### Entry Point
|
||||||
|
**File**: `backend/igny8_core/ai/tasks.py`
|
||||||
|
**Function**: `run_ai_task`
|
||||||
|
**Purpose**: Unified Celery task entrypoint for all AI functions
|
||||||
|
**Parameters**: `function_name` (str), `payload` (dict), `account_id` (int)
|
||||||
|
**Flow**: Loads function from registry → Creates AIEngine → Executes function
|
||||||
|
|
||||||
|
#### Engine Orchestrator
|
||||||
|
**File**: `backend/igny8_core/ai/engine.py`
|
||||||
|
**Class**: `AIEngine`
|
||||||
|
**Purpose**: Central orchestrator managing lifecycle, progress, logging, cost tracking
|
||||||
|
**Methods**:
|
||||||
|
- `execute` - Main execution pipeline (6 phases: INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
||||||
|
- `_handle_error` - Centralized error handling
|
||||||
|
- `_log_to_database` - Logs to AITaskLog model
|
||||||
|
|
||||||
|
#### Base Function Class
|
||||||
|
**File**: `backend/igny8_core/ai/base.py`
|
||||||
|
**Class**: `BaseAIFunction`
|
||||||
|
**Purpose**: Abstract base class defining interface for all AI functions
|
||||||
|
**Abstract Methods**:
|
||||||
|
- `get_name` - Returns function name (e.g., 'auto_cluster')
|
||||||
|
- `prepare` - Loads and prepares data
|
||||||
|
- `build_prompt` - Builds AI prompt
|
||||||
|
- `parse_response` - Parses AI response
|
||||||
|
- `save_output` - Saves results to database
|
||||||
|
**Optional Methods**:
|
||||||
|
- `get_metadata` - Returns display name, description, phases
|
||||||
|
- `get_max_items` - Returns max items limit (or None)
|
||||||
|
- `validate` - Validates input payload (default: checks for 'ids')
|
||||||
|
- `get_model` - Returns model override (default: None, uses account default)
|
||||||
|
|
||||||
|
#### Function Registry
|
||||||
|
**File**: `backend/igny8_core/ai/registry.py`
|
||||||
|
**Functions**:
|
||||||
|
- `register_function` - Registers function class
|
||||||
|
- `register_lazy_function` - Registers lazy loader
|
||||||
|
- `get_function` - Gets function class by name (lazy loads if needed)
|
||||||
|
- `get_function_instance` - Gets function instance by name
|
||||||
|
- `list_functions` - Lists all registered functions
|
||||||
|
|
||||||
|
#### AI Core Handler
|
||||||
|
**File**: `backend/igny8_core/ai/ai_core.py`
|
||||||
|
**Class**: `AICore`
|
||||||
|
**Purpose**: Centralized AI request handler for all AI operations (text and image generation)
|
||||||
|
**Methods**:
|
||||||
|
- `run_ai_request` - Makes API call to OpenAI/Runware for text generation
|
||||||
|
- `generate_image` - Makes API call to OpenAI DALL-E or Runware for image generation
|
||||||
|
- `extract_json` - Extracts JSON from response (handles markdown code blocks)
|
||||||
|
|
||||||
|
#### Prompt Registry
|
||||||
|
**File**: `backend/igny8_core/ai/prompts.py`
|
||||||
|
**Class**: `PromptRegistry`
|
||||||
|
**Purpose**: Centralized prompt management with hierarchical resolution
|
||||||
|
**Method**: `get_prompt` - Gets prompt with resolution order:
|
||||||
|
1. Task-level prompt_override (if exists)
|
||||||
|
2. DB prompt for (account, function)
|
||||||
|
3. Default fallback from DEFAULT_PROMPTS registry
|
||||||
|
**Prompt Types**:
|
||||||
|
- `clustering` - For auto_cluster function
|
||||||
|
- `ideas` - For generate_ideas function
|
||||||
|
- `content_generation` - For generate_content function
|
||||||
|
- `image_prompt_extraction` - For extract_image_prompts function
|
||||||
|
- `image_prompt_template` - Template for formatting image prompts
|
||||||
|
- `negative_prompt` - Negative prompt for Runware image generation
|
||||||
|
|
||||||
|
#### Model Settings
|
||||||
|
**File**: `backend/igny8_core/ai/settings.py`
|
||||||
|
**Constants**: `MODEL_CONFIG` - Model configurations per function (model, max_tokens, temperature, response_format)
|
||||||
|
**Functions**:
|
||||||
|
- `get_model_config` - Gets model config for function (reads from IntegrationSettings if account provided)
|
||||||
|
- `get_model` - Gets model name for function
|
||||||
|
- `get_max_tokens` - Gets max tokens for function
|
||||||
|
- `get_temperature` - Gets temperature for function
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Function Execution Flow
|
||||||
|
|
||||||
|
### Complete Execution Pipeline
|
||||||
|
|
||||||
|
```
|
||||||
|
1. API Endpoint (views.py)
|
||||||
|
↓
|
||||||
|
2. run_ai_task (tasks.py)
|
||||||
|
- Gets account from account_id
|
||||||
|
- Gets function instance from registry
|
||||||
|
- Creates AIEngine
|
||||||
|
↓
|
||||||
|
3. AIEngine.execute (engine.py)
|
||||||
|
Phase 1: INIT (0-10%)
|
||||||
|
- Calls function.validate()
|
||||||
|
- Updates progress tracker
|
||||||
|
↓
|
||||||
|
Phase 2: PREP (10-25%)
|
||||||
|
- Calls function.prepare()
|
||||||
|
- Calls function.build_prompt()
|
||||||
|
- Updates progress tracker
|
||||||
|
↓
|
||||||
|
Phase 3: AI_CALL (25-70%)
|
||||||
|
- Gets model config from settings
|
||||||
|
- Calls AICore.run_ai_request() or AICore.generate_image()
|
||||||
|
- Tracks cost and tokens
|
||||||
|
- Updates progress tracker
|
||||||
|
↓
|
||||||
|
Phase 4: PARSE (70-85%)
|
||||||
|
- Calls function.parse_response()
|
||||||
|
- Updates progress tracker
|
||||||
|
↓
|
||||||
|
Phase 5: SAVE (85-98%)
|
||||||
|
- Calls function.save_output()
|
||||||
|
- Logs credit usage
|
||||||
|
- Updates progress tracker
|
||||||
|
↓
|
||||||
|
Phase 6: DONE (98-100%)
|
||||||
|
- Logs to AITaskLog
|
||||||
|
- Returns result
|
||||||
|
```
|
||||||
|
|
||||||
|
### Progress Updates
|
||||||
|
|
||||||
|
**Progress Endpoint**: `/api/v1/system/settings/task_progress/{task_id}/`
|
||||||
|
|
||||||
|
**Response Format**:
|
||||||
|
- `state`: Task state (PENDING, PROGRESS, SUCCESS, FAILURE)
|
||||||
|
- `meta`: Progress metadata
|
||||||
|
- `phase`: Current phase (INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
||||||
|
- `percentage`: Progress percentage (0-100)
|
||||||
|
- `message`: User-friendly message
|
||||||
|
- `request_steps`: Array of request steps
|
||||||
|
- `response_steps`: Array of response steps
|
||||||
|
- `cost`: API cost in USD
|
||||||
|
- `tokens`: Token count
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Functions
|
||||||
|
|
||||||
|
### 1. Auto Cluster Keywords
|
||||||
|
|
||||||
|
**Purpose**: Group related keywords into semantic clusters using AI
|
||||||
|
|
||||||
|
**Function Class**: `AutoClusterFunction`
|
||||||
|
**File**: `backend/igny8_core/ai/functions/auto_cluster.py`
|
||||||
|
|
||||||
|
**API Endpoint**:
|
||||||
|
- **ViewSet**: `KeywordViewSet`
|
||||||
|
- **Action**: `auto_cluster`
|
||||||
|
- **Method**: POST
|
||||||
|
- **URL Path**: `/v1/planner/keywords/auto_cluster/`
|
||||||
|
- **Payload**: `ids` (list[int]) - Keyword IDs
|
||||||
|
|
||||||
|
**Function Methods**:
|
||||||
|
- `get_name()`: Returns `'auto_cluster'`
|
||||||
|
- `validate(payload, account)`: Validates keyword IDs exist
|
||||||
|
- `prepare(payload, account)`: Loads keywords from database
|
||||||
|
- `build_prompt(data, account)`: Builds clustering prompt with keyword data
|
||||||
|
- `parse_response(response, step_tracker)`: Parses cluster JSON response
|
||||||
|
- `save_output(parsed, original_data, account, progress_tracker, step_tracker)`: Creates Cluster records and links keywords
|
||||||
|
|
||||||
|
**Input**: List of keyword IDs
|
||||||
|
**Output**: Cluster records created, keywords linked to clusters
|
||||||
|
|
||||||
|
**Progress Messages**:
|
||||||
|
- INIT: "Validating keywords"
|
||||||
|
- PREP: "Preparing keyword clustering"
|
||||||
|
- AI_CALL: "Analyzing keyword relationships"
|
||||||
|
- PARSE: "Processing cluster data"
|
||||||
|
- SAVE: "Creating clusters"
|
||||||
|
|
||||||
|
### 2. Generate Ideas
|
||||||
|
|
||||||
|
**Purpose**: Generate content ideas from keyword clusters
|
||||||
|
|
||||||
|
**Function Class**: `GenerateIdeasFunction`
|
||||||
|
**File**: `backend/igny8_core/ai/functions/generate_ideas.py`
|
||||||
|
|
||||||
|
**API Endpoint**:
|
||||||
|
- **ViewSet**: `ClusterViewSet`
|
||||||
|
- **Action**: `auto_generate_ideas`
|
||||||
|
- **Method**: POST
|
||||||
|
- **URL Path**: `/v1/planner/clusters/auto_generate_ideas/`
|
||||||
|
- **Payload**: `ids` (list[int]) - Cluster IDs
|
||||||
|
|
||||||
|
**Function Methods**:
|
||||||
|
- `get_name()`: Returns `'generate_ideas'`
|
||||||
|
- `validate(payload, account)`: Validates cluster IDs exist
|
||||||
|
- `prepare(payload, account)`: Loads clusters and keywords
|
||||||
|
- `build_prompt(data, account)`: Builds idea generation prompt with cluster data
|
||||||
|
- `parse_response(response, step_tracker)`: Parses ideas JSON response
|
||||||
|
- `save_output(parsed, original_data, account, progress_tracker, step_tracker)`: Creates ContentIdeas records
|
||||||
|
|
||||||
|
**Input**: List of cluster IDs
|
||||||
|
**Output**: ContentIdeas records created
|
||||||
|
|
||||||
|
**Progress Messages**:
|
||||||
|
- INIT: "Verifying cluster integrity"
|
||||||
|
- PREP: "Loading cluster keywords"
|
||||||
|
- AI_CALL: "Generating ideas with Igny8 Semantic AI"
|
||||||
|
- PARSE: "{count} high-opportunity idea(s) generated"
|
||||||
|
- SAVE: "Content Outline for Ideas generated"
|
||||||
|
|
||||||
|
### 3. Generate Content
|
||||||
|
|
||||||
|
**Purpose**: Generate blog post and article content from tasks
|
||||||
|
|
||||||
|
**Function Class**: `GenerateContentFunction`
|
||||||
|
**File**: `backend/igny8_core/ai/functions/generate_content.py`
|
||||||
|
|
||||||
|
**API Endpoint**:
|
||||||
|
- **ViewSet**: `TasksViewSet`
|
||||||
|
- **Action**: `auto_generate_content`
|
||||||
|
- **Method**: POST
|
||||||
|
- **URL Path**: `/v1/writer/tasks/auto_generate_content/`
|
||||||
|
- **Payload**: `ids` (list[int]) - Task IDs (max 50)
|
||||||
|
|
||||||
|
**Function Methods**:
|
||||||
|
- `get_name()`: Returns `'generate_content'`
|
||||||
|
- `get_max_items()`: Returns `50` (max tasks per batch)
|
||||||
|
- `validate(payload, account)`: Validates task IDs exist
|
||||||
|
- `prepare(payload, account)`: Loads tasks with related data
|
||||||
|
- `build_prompt(data, account)`: Builds content generation prompt with task data
|
||||||
|
- `parse_response(response, step_tracker)`: Parses content (JSON or plain text)
|
||||||
|
- `save_output(parsed, original_data, account, progress_tracker, step_tracker)`: Creates/updates Content records
|
||||||
|
|
||||||
|
**Input**: List of task IDs
|
||||||
|
**Output**: Content records created/updated with HTML content
|
||||||
|
|
||||||
|
**Progress Messages**:
|
||||||
|
- INIT: "Initializing content generation"
|
||||||
|
- PREP: "Loading tasks and building prompts"
|
||||||
|
- AI_CALL: "Generating content with AI"
|
||||||
|
- PARSE: "Processing content"
|
||||||
|
- SAVE: "Saving content"
|
||||||
|
|
||||||
|
### 4. Generate Image Prompts
|
||||||
|
|
||||||
|
**Purpose**: Extract image prompts from content for generating images
|
||||||
|
|
||||||
|
**Function Class**: `GenerateImagePromptsFunction`
|
||||||
|
**File**: `backend/igny8_core/ai/functions/generate_image_prompts.py`
|
||||||
|
|
||||||
|
**API Endpoint**:
|
||||||
|
- **ViewSet**: `TasksViewSet` (via content)
|
||||||
|
- **Action**: `generate_image_prompts`
|
||||||
|
- **Method**: POST
|
||||||
|
- **URL Path**: `/v1/writer/content/generate_image_prompts/`
|
||||||
|
- **Payload**: `ids` (list[int]) - Content IDs
|
||||||
|
|
||||||
|
**Function Methods**:
|
||||||
|
- `get_name()`: Returns `'generate_image_prompts'`
|
||||||
|
- `validate(payload, account)`: Validates content IDs exist
|
||||||
|
- `prepare(payload, account)`: Loads content records
|
||||||
|
- `build_prompt(data, account)`: Builds prompt extraction prompt with content HTML
|
||||||
|
- `parse_response(response, step_tracker)`: Parses image prompts JSON
|
||||||
|
- `save_output(parsed, original_data, account, progress_tracker, step_tracker)`: Updates Images records with prompts
|
||||||
|
|
||||||
|
**Input**: List of content IDs
|
||||||
|
**Output**: Images records updated with prompts (featured, in-article)
|
||||||
|
|
||||||
|
**Progress Messages**:
|
||||||
|
- INIT: "Validating content"
|
||||||
|
- PREP: "Preparing image prompt extraction"
|
||||||
|
- AI_CALL: "Extracting image prompts"
|
||||||
|
- PARSE: "Processing image prompts"
|
||||||
|
- SAVE: "Saving image prompts"
|
||||||
|
|
||||||
|
### 5. Generate Images
|
||||||
|
|
||||||
|
**Purpose**: Generate images using AI (OpenAI DALL-E or Runware) based on prompts
|
||||||
|
|
||||||
|
**Function Class**: `GenerateImagesFunction`
|
||||||
|
**File**: `backend/igny8_core/ai/functions/generate_images.py`
|
||||||
|
|
||||||
|
**API Endpoint**:
|
||||||
|
- **ViewSet**: `ImagesViewSet`
|
||||||
|
- **Action**: `generate_images`
|
||||||
|
- **Method**: POST
|
||||||
|
- **URL Path**: `/v1/writer/images/generate_images/`
|
||||||
|
- **Payload**: `ids` (list[int]) - Image IDs
|
||||||
|
|
||||||
|
**Function Methods**:
|
||||||
|
- `get_name()`: Returns `'generate_images'`
|
||||||
|
- `validate(payload, account)`: Validates image IDs exist and have prompts
|
||||||
|
- `prepare(payload, account)`: Loads images with prompts
|
||||||
|
- `build_prompt(data, account)`: Formats image prompt with context
|
||||||
|
- `parse_response(response, step_tracker)`: Parses image URL from API response
|
||||||
|
- `save_output(parsed, original_data, account, progress_tracker, step_tracker)`: Updates Images records with image URLs
|
||||||
|
|
||||||
|
**Input**: List of image IDs (with prompts)
|
||||||
|
**Output**: Images records updated with image URLs
|
||||||
|
|
||||||
|
**Image Generation Settings**:
|
||||||
|
- Provider: 'openai' or 'runware'
|
||||||
|
- Model: Model name (e.g., 'dall-e-3', 'runware:97@1')
|
||||||
|
- Image Type: 'realistic', 'artistic', 'cartoon'
|
||||||
|
- Max In-Article Images: Max images per content
|
||||||
|
- Image Format: 'webp', 'jpg', 'png'
|
||||||
|
- Desktop/Mobile: Boolean flags
|
||||||
|
|
||||||
|
**Progress Messages**:
|
||||||
|
- INIT: "Validating image prompts"
|
||||||
|
- PREP: "Preparing image generation"
|
||||||
|
- AI_CALL: "Creating image(s) with AI"
|
||||||
|
- PARSE: "Processing image response"
|
||||||
|
- SAVE: "Saving generated image(s)"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Progress Tracking
|
||||||
|
|
||||||
|
### Progress Phases
|
||||||
|
|
||||||
|
All AI functions follow the same 6-phase execution:
|
||||||
|
|
||||||
|
1. **INIT** (0-10%): Validation phase
|
||||||
|
2. **PREP** (10-25%): Data preparation phase
|
||||||
|
3. **AI_CALL** (25-70%): AI API call phase
|
||||||
|
4. **PARSE** (70-85%): Response parsing phase
|
||||||
|
5. **SAVE** (85-98%): Database save phase
|
||||||
|
6. **DONE** (98-100%): Completion phase
|
||||||
|
|
||||||
|
### Progress Updates
|
||||||
|
|
||||||
|
**Frontend Polling**: Frontend polls `/api/v1/system/settings/task_progress/{task_id}/` every 1-2 seconds
|
||||||
|
|
||||||
|
**Progress Response**:
|
||||||
|
- `state`: Task state
|
||||||
|
- `meta`: Progress metadata
|
||||||
|
- `phase`: Current phase
|
||||||
|
- `percentage`: Progress percentage
|
||||||
|
- `message`: User-friendly message
|
||||||
|
- `request_steps`: Request steps array
|
||||||
|
- `response_steps`: Response steps array
|
||||||
|
- `cost`: API cost
|
||||||
|
- `tokens`: Token count
|
||||||
|
|
||||||
|
### Step Tracking
|
||||||
|
|
||||||
|
**Request Steps**: Tracked during prompt building and AI call
|
||||||
|
**Response Steps**: Tracked during response parsing
|
||||||
|
|
||||||
|
**Purpose**: Provides detailed logging for debugging and transparency
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cost Tracking
|
||||||
|
|
||||||
|
### Cost Calculation
|
||||||
|
|
||||||
|
**Text Generation**:
|
||||||
|
- Cost calculated based on model pricing (input tokens + output tokens)
|
||||||
|
- Tracked per request
|
||||||
|
- Stored in `CostTracker`
|
||||||
|
|
||||||
|
**Image Generation**:
|
||||||
|
- Cost calculated based on provider pricing
|
||||||
|
- OpenAI DALL-E: Fixed cost per image
|
||||||
|
- Runware: Variable cost per image
|
||||||
|
- Tracked per image
|
||||||
|
|
||||||
|
### Cost Storage
|
||||||
|
|
||||||
|
**AITaskLog Model**:
|
||||||
|
- `cost`: Total cost for task
|
||||||
|
- `tokens`: Total tokens used
|
||||||
|
|
||||||
|
**CreditUsageLog Model**:
|
||||||
|
- `cost_usd`: Cost in USD
|
||||||
|
- `credits_used`: Credits deducted
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt Management
|
||||||
|
|
||||||
|
### Prompt Resolution Order
|
||||||
|
|
||||||
|
1. **Task-Level Override**: If task has `prompt_override`, use it
|
||||||
|
2. **Database Prompt**: If account has custom prompt in database, use it
|
||||||
|
3. **Default Prompt**: Use default prompt from `DEFAULT_PROMPTS` registry
|
||||||
|
|
||||||
|
### Prompt Customization
|
||||||
|
|
||||||
|
**Per Account**: Custom prompts stored in `AIPrompt` model
|
||||||
|
**Per Function**: Different prompts for each function type
|
||||||
|
**Context Variables**: Prompts support context placeholders:
|
||||||
|
- `[IGNY8_KEYWORDS]` - Keyword list
|
||||||
|
- `[IGNY8_CLUSTERS]` - Cluster list
|
||||||
|
- `[IGNY8_CLUSTER_KEYWORDS]` - Cluster keywords
|
||||||
|
- `[IGNY8_IDEA]` - Idea data
|
||||||
|
- `[IGNY8_CLUSTER]` - Cluster data
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Model Configuration
|
||||||
|
|
||||||
|
### Model Settings
|
||||||
|
|
||||||
|
**Default Models**:
|
||||||
|
- Clustering: `gpt-4o-mini`
|
||||||
|
- Ideas: `gpt-4o-mini`
|
||||||
|
- Content: `gpt-4o`
|
||||||
|
- Image Prompts: `gpt-4o-mini`
|
||||||
|
- Images: `dall-e-3` (OpenAI) or `runware:97@1` (Runware)
|
||||||
|
|
||||||
|
### Per-Account Override
|
||||||
|
|
||||||
|
**IntegrationSettings Model**:
|
||||||
|
- `integration_type`: 'openai' or 'runware'
|
||||||
|
- `config`: JSONField with model configuration
|
||||||
|
- `model`: Model name
|
||||||
|
- `max_tokens`: Max tokens
|
||||||
|
- `temperature`: Temperature
|
||||||
|
- `response_format`: Response format
|
||||||
|
|
||||||
|
### Model Configuration
|
||||||
|
|
||||||
|
**File**: `backend/igny8_core/ai/settings.py`
|
||||||
|
|
||||||
|
**MODEL_CONFIG**: Dictionary mapping function names to model configurations
|
||||||
|
|
||||||
|
**Functions**:
|
||||||
|
- `get_model_config(function_name, account=None)`: Gets model config (checks IntegrationSettings if account provided)
|
||||||
|
- `get_model(function_name, account=None)`: Gets model name
|
||||||
|
- `get_max_tokens(function_name, account=None)`: Gets max tokens
|
||||||
|
- `get_temperature(function_name, account=None)`: Gets temperature
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The IGNY8 AI framework provides:
|
||||||
|
|
||||||
|
1. **Unified Interface**: All AI functions use the same execution pipeline
|
||||||
|
2. **Consistent Execution**: All functions follow the same 6-phase flow
|
||||||
|
3. **Progress Tracking**: Real-time progress updates via Celery
|
||||||
|
4. **Cost Tracking**: Automatic cost and token tracking
|
||||||
|
5. **Error Handling**: Centralized error handling in AIEngine
|
||||||
|
6. **Prompt Management**: Hierarchical prompt resolution
|
||||||
|
7. **Model Configuration**: Per-account model overrides
|
||||||
|
8. **Database Logging**: Automatic logging to AITaskLog
|
||||||
|
9. **Extensibility**: Easy to add new AI functions
|
||||||
|
10. **Reliability**: Retry logic and error recovery
|
||||||
|
|
||||||
|
This architecture ensures consistency, maintainability, and extensibility while providing a robust foundation for all AI operations in the IGNY8 platform.
|
||||||
|
|
||||||
173
docs/06-CHANGELOG.md
Normal file
173
docs/06-CHANGELOG.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
# IGNY8 Changelog
|
||||||
|
|
||||||
|
**Last Updated:** 2025-01-XX
|
||||||
|
**Purpose:** System changelog documenting features, updates, and improvements.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [2025-01-XX - Documentation Consolidation](#2025-01-xx---documentation-consolidation)
|
||||||
|
2. [System Features](#system-features)
|
||||||
|
3. [Planned Features](#planned-features)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2025-01-XX - Documentation Consolidation
|
||||||
|
|
||||||
|
### Documentation Updates
|
||||||
|
|
||||||
|
- **Consolidated Documentation**: All documentation consolidated into single structure
|
||||||
|
- `docs/README.md` - Documentation index
|
||||||
|
- `docs/01-ARCHITECTURE-TECH-STACK.md` - Architecture and tech stack
|
||||||
|
- `docs/02-APP-ARCHITECTURE.md` - Application architecture with workflows
|
||||||
|
- `docs/03-FRONTEND.md` - Frontend documentation
|
||||||
|
- `docs/04-BACKEND.md` - Backend documentation
|
||||||
|
- `docs/05-AI-FUNCTIONS.md` - AI functions documentation
|
||||||
|
- `docs/06-CHANGELOG.md` - System changelog
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
- **Complete Workflow Documentation**: All workflows documented from start to finish
|
||||||
|
- **Feature Completeness**: All features documented without missing any flows
|
||||||
|
- **No Code Snippets**: Documentation focuses on workflows and features (no code)
|
||||||
|
- **Accurate State**: Documentation reflects current system state
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Features
|
||||||
|
|
||||||
|
### Implemented Features
|
||||||
|
|
||||||
|
#### Foundation
|
||||||
|
- ✅ Multi-tenancy system with account isolation
|
||||||
|
- ✅ Authentication (login/register) with JWT
|
||||||
|
- ✅ RBAC permissions (Developer, Owner, Admin, Editor, Viewer, System Bot)
|
||||||
|
- ✅ Account > Site > Sector hierarchy
|
||||||
|
- ✅ Multiple sites can be active simultaneously
|
||||||
|
- ✅ Maximum 5 active sectors per site
|
||||||
|
|
||||||
|
#### Planner Module
|
||||||
|
- ✅ Keywords CRUD operations
|
||||||
|
- ✅ Keyword import/export (CSV)
|
||||||
|
- ✅ Keyword filtering and organization
|
||||||
|
- ✅ AI-powered keyword clustering
|
||||||
|
- ✅ Clusters CRUD operations
|
||||||
|
- ✅ Content ideas generation from clusters
|
||||||
|
- ✅ Content ideas CRUD operations
|
||||||
|
- ✅ Keyword-to-cluster mapping
|
||||||
|
- ✅ Cluster metrics and analytics
|
||||||
|
|
||||||
|
#### Writer Module
|
||||||
|
- ✅ Tasks CRUD operations
|
||||||
|
- ✅ AI-powered content generation
|
||||||
|
- ✅ Content editing and review
|
||||||
|
- ✅ Image prompt extraction
|
||||||
|
- ✅ AI-powered image generation (OpenAI DALL-E, Runware)
|
||||||
|
- ✅ Image management
|
||||||
|
- ✅ WordPress integration (publishing)
|
||||||
|
|
||||||
|
#### Thinker Module
|
||||||
|
- ✅ AI prompt management
|
||||||
|
- ✅ Author profile management
|
||||||
|
- ✅ Content strategy management
|
||||||
|
- ✅ Image generation testing
|
||||||
|
|
||||||
|
#### System Module
|
||||||
|
- ✅ Integration settings (OpenAI, Runware)
|
||||||
|
- ✅ API key configuration
|
||||||
|
- ✅ Connection testing
|
||||||
|
- ✅ System status and monitoring
|
||||||
|
|
||||||
|
#### Billing Module
|
||||||
|
- ✅ Credit balance tracking
|
||||||
|
- ✅ Credit transactions
|
||||||
|
- ✅ Usage logging
|
||||||
|
- ✅ Cost tracking
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
- ✅ Configuration-driven UI system
|
||||||
|
- ✅ 4 universal templates (Dashboard, Table, Form, System)
|
||||||
|
- ✅ Complete component library
|
||||||
|
- ✅ Zustand state management
|
||||||
|
- ✅ React Router v6 routing
|
||||||
|
- ✅ Progress tracking for AI tasks
|
||||||
|
- ✅ AI Request/Response Logs
|
||||||
|
- ✅ Responsive design
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
- ✅ RESTful API with DRF
|
||||||
|
- ✅ Automatic account isolation
|
||||||
|
- ✅ Site access control
|
||||||
|
- ✅ Celery async task processing
|
||||||
|
- ✅ Progress tracking for Celery tasks
|
||||||
|
- ✅ Unified AI framework
|
||||||
|
- ✅ Database logging
|
||||||
|
|
||||||
|
#### AI Functions
|
||||||
|
- ✅ Auto Cluster Keywords
|
||||||
|
- ✅ Generate Ideas
|
||||||
|
- ✅ Generate Content
|
||||||
|
- ✅ Generate Image Prompts
|
||||||
|
- ✅ Generate Images
|
||||||
|
- ✅ Test OpenAI connection
|
||||||
|
- ✅ Test Runware connection
|
||||||
|
- ✅ Test image generation
|
||||||
|
|
||||||
|
#### Infrastructure
|
||||||
|
- ✅ Docker-based containerization
|
||||||
|
- ✅ Two-stack architecture (infra, app)
|
||||||
|
- ✅ Caddy reverse proxy
|
||||||
|
- ✅ PostgreSQL database
|
||||||
|
- ✅ Redis cache and Celery broker
|
||||||
|
- ✅ pgAdmin database administration
|
||||||
|
- ✅ FileBrowser file management
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Planned Features
|
||||||
|
|
||||||
|
### In Progress
|
||||||
|
|
||||||
|
- 🔄 Planner Dashboard enhancement with KPIs
|
||||||
|
- 🔄 WordPress integration (publishing) - partial implementation
|
||||||
|
- 🔄 Automation & CRON tasks
|
||||||
|
|
||||||
|
### Future
|
||||||
|
|
||||||
|
- 📋 Analytics module enhancements
|
||||||
|
- 📋 Advanced scheduling features
|
||||||
|
- 📋 Additional AI model integrations
|
||||||
|
- 📋 Stripe payment integration
|
||||||
|
- 📋 Plan limits enforcement
|
||||||
|
- 📋 Rate limiting
|
||||||
|
- 📋 Advanced reporting
|
||||||
|
- 📋 Mobile app support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
### Current Version
|
||||||
|
|
||||||
|
**Version**: 1.0
|
||||||
|
**Date**: 2025-01-XX
|
||||||
|
**Status**: Production
|
||||||
|
|
||||||
|
### Key Milestones
|
||||||
|
|
||||||
|
- **2025-01-XX**: Documentation consolidation
|
||||||
|
- **2025-01-XX**: AI framework implementation
|
||||||
|
- **2025-01-XX**: Multi-tenancy system
|
||||||
|
- **2025-01-XX**: Frontend configuration system
|
||||||
|
- **2025-01-XX**: Docker deployment setup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All features are documented in detail in the respective documentation files
|
||||||
|
- Workflows are complete and accurate
|
||||||
|
- System is production-ready
|
||||||
|
- Documentation is maintained and updated regularly
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,501 +0,0 @@
|
|||||||
# Image Generation Implementation Changelog
|
|
||||||
|
|
||||||
## Stage 1: Pre-Queue Modal Display - Completed ✅
|
|
||||||
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Status:** Completed
|
|
||||||
**Goal:** Open modal immediately showing all progress bars before any API calls
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Changes Made
|
|
||||||
|
|
||||||
### 1. Frontend Components
|
|
||||||
|
|
||||||
#### Created: `frontend/src/components/common/ImageQueueModal.tsx`
|
|
||||||
- **Purpose:** Display image generation queue with individual progress bars
|
|
||||||
- **Features:**
|
|
||||||
- Shows all images that will be generated with individual progress bars
|
|
||||||
- Displays queue number, label, content title, status, and progress percentage
|
|
||||||
- Includes thumbnail placeholder for generated images
|
|
||||||
- Supports 4 states: `pending`, `processing`, `completed`, `failed`
|
|
||||||
- Styled similar to WP plugin's image-queue-processor.js modal
|
|
||||||
- Responsive design with dark mode support
|
|
||||||
- Prevents closing while processing
|
|
||||||
- Shows completion summary in footer
|
|
||||||
|
|
||||||
**Key Props:**
|
|
||||||
- `isOpen`: Boolean to control modal visibility
|
|
||||||
- `onClose`: Callback when modal is closed
|
|
||||||
- `queue`: Array of `ImageQueueItem` objects
|
|
||||||
- `totalImages`: Total number of images in queue
|
|
||||||
- `onUpdateQueue`: Optional callback to update queue state
|
|
||||||
|
|
||||||
**ImageQueueItem Interface:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
imageId: number | null;
|
|
||||||
index: number;
|
|
||||||
label: string;
|
|
||||||
type: 'featured' | 'in_article';
|
|
||||||
position?: number;
|
|
||||||
contentTitle: string;
|
|
||||||
status: 'pending' | 'processing' | 'completed' | 'failed';
|
|
||||||
progress: number; // 0-100
|
|
||||||
imageUrl: string | null;
|
|
||||||
error: string | null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Updated: `frontend/src/pages/Writer/Images.tsx`
|
|
||||||
- **Added Imports:**
|
|
||||||
- `fetchImageGenerationSettings` from `../../services/api`
|
|
||||||
- `ImageQueueModal` and `ImageQueueItem` from `../../components/common/ImageQueueModal`
|
|
||||||
|
|
||||||
- **Added State:**
|
|
||||||
```typescript
|
|
||||||
const [isQueueModalOpen, setIsQueueModalOpen] = useState(false);
|
|
||||||
const [imageQueue, setImageQueue] = useState<ImageQueueItem[]>([]);
|
|
||||||
const [currentContentId, setCurrentContentId] = useState<number | null>(null);
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Added Function: `buildImageQueue()`**
|
|
||||||
- Builds image queue structure from content images
|
|
||||||
- Includes featured image (if pending and has prompt)
|
|
||||||
- Includes in-article images (up to `max_in_article_images` from settings)
|
|
||||||
- Sorts in-article images by position
|
|
||||||
- Returns array of `ImageQueueItem` objects
|
|
||||||
|
|
||||||
- **Updated Function: `handleGenerateImages()`**
|
|
||||||
- **Stage 1 Implementation:**
|
|
||||||
1. Fetches image generation settings to get `max_in_article_images`
|
|
||||||
2. Builds image queue using `buildImageQueue()`
|
|
||||||
3. Opens modal immediately with all progress bars at 0%
|
|
||||||
4. Collects image IDs for future API call (Stage 2)
|
|
||||||
5. Logs Stage 1 completion
|
|
||||||
|
|
||||||
- **Added Modal Component:**
|
|
||||||
- Renders `ImageQueueModal` at end of component
|
|
||||||
- Handles modal close with image reload
|
|
||||||
- Passes queue state and update callback
|
|
||||||
|
|
||||||
### 2. API Services
|
|
||||||
|
|
||||||
#### Updated: `frontend/src/services/api.ts`
|
|
||||||
- **Added Interface: `ImageGenerationSettings`**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
success: boolean;
|
|
||||||
config: {
|
|
||||||
provider: string;
|
|
||||||
model: string;
|
|
||||||
image_type: string;
|
|
||||||
max_in_article_images: number;
|
|
||||||
image_format: string;
|
|
||||||
desktop_enabled: boolean;
|
|
||||||
mobile_enabled: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Added Function: `fetchImageGenerationSettings()`**
|
|
||||||
- Fetches image generation settings from backend
|
|
||||||
- Endpoint: `/v1/system/integrations/image_generation/`
|
|
||||||
- Returns settings including `max_in_article_images`
|
|
||||||
|
|
||||||
### 3. Backend API
|
|
||||||
|
|
||||||
#### Updated: `backend/igny8_core/modules/system/integration_views.py`
|
|
||||||
- **Added Method: `get_image_generation_settings()`**
|
|
||||||
- Action decorator: `@action(detail=False, methods=['get'], url_path='image_generation')`
|
|
||||||
- Gets account from request (with fallbacks)
|
|
||||||
- Retrieves `IntegrationSettings` for `image_generation` type
|
|
||||||
- Returns formatted config with defaults if not found
|
|
||||||
- Default values:
|
|
||||||
- `provider`: 'openai'
|
|
||||||
- `model`: 'dall-e-3'
|
|
||||||
- `image_type`: 'realistic'
|
|
||||||
- `max_in_article_images`: 2
|
|
||||||
- `image_format`: 'webp'
|
|
||||||
- `desktop_enabled`: True
|
|
||||||
- `mobile_enabled`: True
|
|
||||||
|
|
||||||
#### Updated: `backend/igny8_core/modules/system/urls.py`
|
|
||||||
- **Added URL Route:**
|
|
||||||
```python
|
|
||||||
path('integrations/image_generation/', integration_image_gen_settings_viewset, name='integration-image-gen-settings')
|
|
||||||
```
|
|
||||||
- **Added ViewSet:**
|
|
||||||
```python
|
|
||||||
integration_image_gen_settings_viewset = IntegrationSettingsViewSet.as_view({
|
|
||||||
'get': 'get_image_generation_settings',
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### User Flow:
|
|
||||||
1. User clicks "Generate Images" button on Images page
|
|
||||||
2. System fetches `max_in_article_images` from IntegrationSettings
|
|
||||||
3. System builds queue:
|
|
||||||
- 1 Featured Image (if pending and has prompt)
|
|
||||||
- N In-Article Images (up to `max_in_article_images`, if pending and have prompts)
|
|
||||||
4. **Modal opens immediately** showing all progress bars at 0%
|
|
||||||
5. Each progress bar displays:
|
|
||||||
- Queue number (1, 2, 3...)
|
|
||||||
- Label (Featured Image, In-Article Image 1, etc.)
|
|
||||||
- Content title
|
|
||||||
- Status: "⏳ Pending"
|
|
||||||
- Progress: 0%
|
|
||||||
- Thumbnail placeholder: "No image"
|
|
||||||
|
|
||||||
### Queue Calculation:
|
|
||||||
```
|
|
||||||
Total Images = 1 (featured) + min(pending_in_article_count, max_in_article_images)
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
- Settings: `max_in_article_images = 3`
|
|
||||||
- Content has: 1 featured (pending), 5 in-article (pending)
|
|
||||||
- Queue: 1 featured + 3 in-article = **4 total progress bars**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### Frontend:
|
|
||||||
1. ✅ `frontend/src/components/common/ImageQueueModal.tsx` (NEW)
|
|
||||||
2. ✅ `frontend/src/pages/Writer/Images.tsx` (UPDATED)
|
|
||||||
3. ✅ `frontend/src/services/api.ts` (UPDATED)
|
|
||||||
|
|
||||||
### Backend:
|
|
||||||
1. ✅ `backend/igny8_core/modules/system/integration_views.py` (UPDATED)
|
|
||||||
2. ✅ `backend/igny8_core/modules/system/urls.py` (UPDATED)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [x] Modal opens immediately when "Generate Images" button is clicked
|
|
||||||
- [x] Modal shows correct number of progress bars (1 featured + N in-article)
|
|
||||||
- [x] Progress bars display correct labels and content titles
|
|
||||||
- [x] All progress bars start at 0% with "Pending" status
|
|
||||||
- [x] Modal can be closed (when not processing)
|
|
||||||
- [x] API endpoint returns correct `max_in_article_images` value
|
|
||||||
- [x] Queue respects `max_in_article_images` setting
|
|
||||||
- [x] Only pending images with prompts are included in queue
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps (Stage 2)
|
|
||||||
|
|
||||||
### Planned Features:
|
|
||||||
1. **Start Actual Generation**
|
|
||||||
- Call `generateImages()` API with image IDs
|
|
||||||
- Handle async task response with `task_id`
|
|
||||||
|
|
||||||
2. **Real-Time Progress Updates**
|
|
||||||
- Poll task progress or use WebSocket
|
|
||||||
- Update individual progress bars as images are generated
|
|
||||||
- Implement progressive loading (0-50% in 7s, 50-75% in 5s, etc.)
|
|
||||||
|
|
||||||
3. **Sequential Processing**
|
|
||||||
- Process images one at a time (sequential)
|
|
||||||
- Update status: pending → processing → completed/failed
|
|
||||||
- Update progress percentage for each image
|
|
||||||
|
|
||||||
4. **Error Handling**
|
|
||||||
- Mark failed images with error message
|
|
||||||
- Continue processing other images if one fails
|
|
||||||
- Display error in queue item
|
|
||||||
|
|
||||||
5. **Completion Handling**
|
|
||||||
- Show generated image thumbnails
|
|
||||||
- Update all statuses to completed/failed
|
|
||||||
- Reload images list on modal close
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Stage 1 focuses on **immediate visual feedback** - modal opens instantly
|
|
||||||
- No API calls are made in Stage 1 (only settings fetch)
|
|
||||||
- Queue structure is built client-side from existing image data
|
|
||||||
- Modal is ready to receive progress updates in Stage 2
|
|
||||||
- Design matches WP plugin's image-queue-processor.js modal
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Related Files
|
|
||||||
|
|
||||||
- **Reference Implementation:** `igny8-ai-seo-wp-plugin/assets/js/image-queue-processor.js`
|
|
||||||
- **Implementation Plan:** `docs/IMAGE_GENERATION_IMPLEMENTATION_PLAN.md`
|
|
||||||
- **Backend Function:** `backend/igny8_core/ai/functions/generate_images_from_prompts.py`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Stage 1 Updates: Modal Styling Improvements
|
|
||||||
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Status:** Completed
|
|
||||||
|
|
||||||
### Changes Made:
|
|
||||||
|
|
||||||
1. **Updated Modal Background**
|
|
||||||
- Changed from `bg-black bg-opacity-50` to standard modal backdrop
|
|
||||||
- Now uses `Modal` component with `bg-gray-400/50 backdrop-blur-[32px]` (standard glass effect)
|
|
||||||
- Matches all other modals in the system
|
|
||||||
|
|
||||||
2. **Replaced Emojis with React Icons**
|
|
||||||
- Header: Replaced 🎨 emoji with `FileIcon` component
|
|
||||||
- Pending status: Replaced ⏳ emoji with `TimeIcon` component
|
|
||||||
- Processing status: Added spinning SVG icon
|
|
||||||
- Completed status: Uses `CheckCircleIcon` component
|
|
||||||
- Failed status: Uses `ErrorIcon` component
|
|
||||||
|
|
||||||
3. **Standard Modal Width**
|
|
||||||
- Changed from custom width to `max-w-4xl` (standard modal width)
|
|
||||||
- Uses `Modal` component which provides consistent styling across system
|
|
||||||
|
|
||||||
### Files Modified:
|
|
||||||
- ✅ `frontend/src/components/common/ImageQueueModal.tsx` (UPDATED)
|
|
||||||
|
|
||||||
### Visual Improvements:
|
|
||||||
- Modal now has proper blur/glass backdrop effect
|
|
||||||
- Icons are consistent with system design
|
|
||||||
- Modal width matches other modals in the system
|
|
||||||
- Better visual hierarchy with icon in header
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**End of Stage 1 Changelog**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Stage 2 & 3: Image Generation Execution & Real-Time Progress - Completed ✅
|
|
||||||
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Status:** Completed
|
|
||||||
**Goal:** Execute image generation sequentially and update progress in real-time
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Changes Made
|
|
||||||
|
|
||||||
### 1. Backend API
|
|
||||||
|
|
||||||
#### Updated: `backend/igny8_core/modules/writer/views.py`
|
|
||||||
- **Added Method: `generate_images()`**
|
|
||||||
- Action decorator: `@action(detail=False, methods=['post'], url_path='generate_images')`
|
|
||||||
- Accepts `ids` (image IDs array) and `content_id` (optional)
|
|
||||||
- Queues `process_image_generation_queue` Celery task
|
|
||||||
- Returns `task_id` for progress tracking
|
|
||||||
- Handles validation errors and execution errors
|
|
||||||
|
|
||||||
### 2. Celery Task
|
|
||||||
|
|
||||||
#### Updated: `backend/igny8_core/ai/tasks.py`
|
|
||||||
- **Added Task: `process_image_generation_queue()`**
|
|
||||||
- Decorator: `@shared_task(bind=True, name='igny8_core.ai.tasks.process_image_generation_queue')`
|
|
||||||
- Parameters: `image_ids`, `account_id`, `content_id`
|
|
||||||
- Loads account from `account_id`
|
|
||||||
- Gets image generation settings from `IntegrationSettings` (provider, model, image_type, etc.)
|
|
||||||
- Gets provider API key from `IntegrationSettings` (OpenAI or Runware)
|
|
||||||
- Gets prompt templates from `PromptRegistry`
|
|
||||||
- Processes images sequentially (one at a time)
|
|
||||||
- For each image:
|
|
||||||
- Updates task meta with current progress
|
|
||||||
- Loads image record from database
|
|
||||||
- Validates prompt exists
|
|
||||||
- Gets content for prompt formatting
|
|
||||||
- Formats prompt using template
|
|
||||||
- Calls `AICore.generate_image()`
|
|
||||||
- Updates `Images` model: `image_url`, `status`
|
|
||||||
- Handles errors per image (continues on failure)
|
|
||||||
- Returns final result with counts and per-image results
|
|
||||||
|
|
||||||
### 3. Frontend API
|
|
||||||
|
|
||||||
#### Updated: `frontend/src/services/api.ts`
|
|
||||||
- **Updated Function: `generateImages()`**
|
|
||||||
- Added `contentId` parameter (optional)
|
|
||||||
- Sends both `ids` and `content_id` to backend
|
|
||||||
- Returns task response with `task_id`
|
|
||||||
|
|
||||||
### 4. Frontend Components
|
|
||||||
|
|
||||||
#### Updated: `frontend/src/pages/Writer/Images.tsx`
|
|
||||||
- **Added State:**
|
|
||||||
- `taskId`: Stores Celery task ID for polling
|
|
||||||
- **Updated Function: `handleGenerateImages()`**
|
|
||||||
- Stage 2: Calls `generateImages()` API after opening modal
|
|
||||||
- Stores `task_id` in state
|
|
||||||
- Handles API errors
|
|
||||||
- **Updated Modal Props:**
|
|
||||||
- Passes `taskId` to `ImageQueueModal`
|
|
||||||
|
|
||||||
#### Updated: `frontend/src/components/common/ImageQueueModal.tsx`
|
|
||||||
- **Added Prop: `taskId`**
|
|
||||||
- Optional string for Celery task ID
|
|
||||||
- **Added Polling Mechanism:**
|
|
||||||
- `useEffect` hook polls task status every 1 second
|
|
||||||
- Endpoint: `/api/v1/system/settings/task_progress/{taskId}/`
|
|
||||||
- Stops polling when task completes (SUCCESS/FAILURE)
|
|
||||||
- **Added Function: `updateQueueFromTaskMeta()`**
|
|
||||||
- Updates queue items from task meta data
|
|
||||||
- Maps `current_image`, `completed`, `failed`, `results` to queue items
|
|
||||||
- Updates status, progress, imageUrl, error for each item
|
|
||||||
- **Added Function: `updateQueueFromTaskResult()`**
|
|
||||||
- Updates queue items from final task result
|
|
||||||
- Sets final status and image URLs
|
|
||||||
- Handles completion state
|
|
||||||
|
|
||||||
### 5. Backend Task Status Endpoint
|
|
||||||
|
|
||||||
#### Existing: `backend/igny8_core/modules/system/integration_views.py`
|
|
||||||
- **Method: `task_progress()`**
|
|
||||||
- Already exists and handles Celery task status polling
|
|
||||||
- Returns task state (PENDING, PROGRESS, SUCCESS, FAILURE)
|
|
||||||
- Returns task meta for progress updates
|
|
||||||
- Returns task result on completion
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### User Flow:
|
|
||||||
1. User clicks "Generate Images" button
|
|
||||||
2. **Stage 1:** Modal opens immediately with all progress bars
|
|
||||||
3. **Stage 2:** Frontend calls `generate_images()` API
|
|
||||||
4. Backend queues `process_image_generation_queue` Celery task
|
|
||||||
5. **Stage 3:** Frontend polls task status every 1 second
|
|
||||||
6. Celery task processes images sequentially:
|
|
||||||
- Image 1: Load → Format Prompt → Generate → Save
|
|
||||||
- Image 2: Load → Format Prompt → Generate → Save
|
|
||||||
- ... (continues for all images)
|
|
||||||
7. Task updates meta with progress after each image
|
|
||||||
8. Frontend receives updates and updates modal progress bars
|
|
||||||
9. On completion, modal shows final status for all images
|
|
||||||
10. User closes modal → Images list reloads
|
|
||||||
|
|
||||||
### Data Flow:
|
|
||||||
```
|
|
||||||
Frontend (Images.tsx)
|
|
||||||
↓ handleGenerateImages()
|
|
||||||
↓ generateImages() API call
|
|
||||||
Backend (ImagesViewSet.generate_images)
|
|
||||||
↓ process_image_generation_queue.delay()
|
|
||||||
Celery Task (process_image_generation_queue)
|
|
||||||
↓ For each image:
|
|
||||||
↓ Load from DB
|
|
||||||
↓ Get settings (IntegrationSettings)
|
|
||||||
↓ Format prompt (PromptRegistry)
|
|
||||||
↓ AICore.generate_image()
|
|
||||||
↓ Update Images model (image_url, status)
|
|
||||||
↓ Update task meta
|
|
||||||
Frontend (ImageQueueModal)
|
|
||||||
↓ Poll task_progress endpoint
|
|
||||||
↓ Update queue from meta/result
|
|
||||||
↓ Display progress bars
|
|
||||||
```
|
|
||||||
|
|
||||||
### Progress Updates:
|
|
||||||
- **Task Meta Structure:**
|
|
||||||
- `current_image`: Index of image being processed
|
|
||||||
- `total_images`: Total images in queue
|
|
||||||
- `completed`: Number of completed images
|
|
||||||
- `failed`: Number of failed images
|
|
||||||
- `results`: Array of per-image results
|
|
||||||
- **Per-Image Result:**
|
|
||||||
- `image_id`: Image record ID
|
|
||||||
- `status`: 'completed' or 'failed'
|
|
||||||
- `image_url`: Generated image URL (if successful)
|
|
||||||
- `error`: Error message (if failed)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### Backend:
|
|
||||||
1. ✅ `backend/igny8_core/modules/writer/views.py` (UPDATED)
|
|
||||||
- `generate_images()` method
|
|
||||||
|
|
||||||
2. ✅ `backend/igny8_core/ai/tasks.py` (UPDATED)
|
|
||||||
- `process_image_generation_queue()` task
|
|
||||||
|
|
||||||
### Frontend:
|
|
||||||
1. ✅ `frontend/src/services/api.ts` (UPDATED)
|
|
||||||
- `generateImages()` function
|
|
||||||
|
|
||||||
2. ✅ `frontend/src/pages/Writer/Images.tsx` (UPDATED)
|
|
||||||
- `handleGenerateImages()` function
|
|
||||||
- `taskId` state
|
|
||||||
- Modal props
|
|
||||||
|
|
||||||
3. ✅ `frontend/src/components/common/ImageQueueModal.tsx` (UPDATED)
|
|
||||||
- `taskId` prop
|
|
||||||
- Polling mechanism
|
|
||||||
- `updateQueueFromTaskMeta()` function
|
|
||||||
- `updateQueueFromTaskResult()` function
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Integration Points
|
|
||||||
|
|
||||||
### Settings Integration:
|
|
||||||
- **IntegrationSettings Model:**
|
|
||||||
- `image_generation` type: Provider, model, image_type, max_in_article_images, etc.
|
|
||||||
- `openai` type: API key, model
|
|
||||||
- `runware` type: API key, model
|
|
||||||
|
|
||||||
### Prompt Templates:
|
|
||||||
- **PromptRegistry:**
|
|
||||||
- `get_image_prompt_template()`: Formats prompt with post_title, image_prompt, image_type
|
|
||||||
- `get_negative_prompt()`: Returns negative prompt for Runware
|
|
||||||
|
|
||||||
### Image Storage:
|
|
||||||
- **Images Model:**
|
|
||||||
- `image_url`: Updated with generated image URL
|
|
||||||
- `status`: Updated to 'generated' or 'failed'
|
|
||||||
- `prompt`: Used for generation (already set)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [x] API endpoint accepts image IDs and content ID
|
|
||||||
- [x] Celery task queues successfully
|
|
||||||
- [x] Task processes images sequentially
|
|
||||||
- [x] Task reads settings from IntegrationSettings
|
|
||||||
- [x] Task formats prompts using PromptRegistry
|
|
||||||
- [x] Task calls AICore.generate_image() correctly
|
|
||||||
- [x] Task updates Images model with URLs and status
|
|
||||||
- [x] Task updates meta with progress
|
|
||||||
- [x] Frontend polls task status correctly
|
|
||||||
- [x] Modal updates progress bars in real-time
|
|
||||||
- [x] Modal shows generated image thumbnails
|
|
||||||
- [x] Modal handles errors per image
|
|
||||||
- [x] Modal shows completion summary
|
|
||||||
- [x] Images list reloads after modal close
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Images are processed **sequentially** (one at a time) to respect API rate limits
|
|
||||||
- Each image failure is handled independently (doesn't stop other images)
|
|
||||||
- Progress updates are sent via Celery task meta (polled every 1 second)
|
|
||||||
- Task status endpoint already exists and is reused
|
|
||||||
- Integration settings are read from database (not hardcoded)
|
|
||||||
- Prompt templates support fallback if formatting fails
|
|
||||||
- Image URLs are saved directly to Images model
|
|
||||||
- Status is updated to 'generated' or 'failed' per image
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**End of Stage 2 & 3 Changelog**
|
|
||||||
|
|
||||||
@@ -1,841 +0,0 @@
|
|||||||
# Image Generation Implementation Plan
|
|
||||||
## Complete Plan for Generating Images from Prompts
|
|
||||||
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Scope:** Implement image generation AI function following existing AI framework patterns
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [System Understanding](#1-system-understanding)
|
|
||||||
2. [Architecture Overview](#2-architecture-overview)
|
|
||||||
3. [Implementation Plan](#3-implementation-plan)
|
|
||||||
4. [Technical Details](#4-technical-details)
|
|
||||||
5. [Frontend Integration](#5-frontend-integration)
|
|
||||||
6. [Testing Strategy](#6-testing-strategy)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. System Understanding
|
|
||||||
|
|
||||||
### 1.1 Current AI Framework Architecture
|
|
||||||
|
|
||||||
The system uses a unified AI framework with the following components:
|
|
||||||
|
|
||||||
**Core Flow:**
|
|
||||||
```
|
|
||||||
Frontend API Call
|
|
||||||
↓
|
|
||||||
views.py (@action endpoint)
|
|
||||||
↓
|
|
||||||
run_ai_task (ai/tasks.py) - Unified Celery task entrypoint
|
|
||||||
↓
|
|
||||||
AIEngine (ai/engine.py) - Orchestrator (6 phases: INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
|
||||||
↓
|
|
||||||
BaseAIFunction implementation
|
|
||||||
↓
|
|
||||||
AICore (ai/ai_core.py) - Centralized AI request handler
|
|
||||||
↓
|
|
||||||
AI Provider (OpenAI/Runware)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Existing AI Functions:**
|
|
||||||
1. **AutoClusterFunction** (`auto_cluster.py`) - Groups keywords into clusters
|
|
||||||
2. **GenerateIdeasFunction** (`generate_ideas.py`) - Generates content ideas from clusters
|
|
||||||
3. **GenerateContentFunction** (`generate_content.py`) - Generates article content from ideas
|
|
||||||
4. **GenerateImagePromptsFunction** (`generate_image_prompts.py`) - Extracts image prompts from content
|
|
||||||
|
|
||||||
**Key Components:**
|
|
||||||
- **BaseAIFunction** - Abstract base class with methods: `get_name()`, `validate()`, `prepare()`, `build_prompt()`, `parse_response()`, `save_output()`
|
|
||||||
- **AIEngine** - Manages lifecycle, progress tracking, cost tracking, error handling
|
|
||||||
- **PromptRegistry** - Centralized prompt management with hierarchy (task → DB → default)
|
|
||||||
- **AICore** - Handles API calls to OpenAI/Runware for both text and image generation
|
|
||||||
- **IntegrationSettings** - Stores account-specific configurations (models, API keys, image settings)
|
|
||||||
|
|
||||||
### 1.2 Image Generation System (WordPress Plugin Reference)
|
|
||||||
|
|
||||||
**Key Learnings from WP Plugin:**
|
|
||||||
|
|
||||||
1. **Queue-Based Processing:**
|
|
||||||
- Images are processed sequentially in a queue
|
|
||||||
- Each image has its own progress bar (0-50% in 7s, 50-75% in 5s, 75-95% incrementally)
|
|
||||||
- Progress modal shows all images being processed with individual status
|
|
||||||
|
|
||||||
2. **Image Types:**
|
|
||||||
- Featured image (1 per content)
|
|
||||||
- In-article images (configurable: 1-5 per content)
|
|
||||||
- Desktop images (if enabled)
|
|
||||||
- Mobile images (if enabled)
|
|
||||||
|
|
||||||
3. **Settings from IntegrationSettings:**
|
|
||||||
- `provider`: 'openai' or 'runware'
|
|
||||||
- `model`: Model name (e.g., 'dall-e-3', 'runware:97@1')
|
|
||||||
- `image_type`: 'realistic', 'artistic', 'cartoon'
|
|
||||||
- `max_in_article_images`: 1-5
|
|
||||||
- `image_format`: 'webp', 'jpg', 'png'
|
|
||||||
- `desktop_enabled`: boolean
|
|
||||||
- `mobile_enabled`: boolean
|
|
||||||
|
|
||||||
4. **Prompt Templates:**
|
|
||||||
- `image_prompt_template`: Template for formatting prompts (uses {post_title}, {image_prompt}, {image_type})
|
|
||||||
- `negative_prompt`: Negative prompt for Runware (OpenAI doesn't support)
|
|
||||||
|
|
||||||
5. **Progress Tracking:**
|
|
||||||
- Real-time progress updates via Celery
|
|
||||||
- Individual image status tracking
|
|
||||||
- Success/failure per image
|
|
||||||
|
|
||||||
### 1.3 Current Image Generation Function
|
|
||||||
|
|
||||||
**Existing:** `GenerateImagesFunction` (`generate_images.py`)
|
|
||||||
- **Status:** Partially implemented, uses old pattern
|
|
||||||
- **Issues:**
|
|
||||||
- Still references `Tasks` instead of `Content`
|
|
||||||
- Doesn't follow the new unified framework pattern
|
|
||||||
- Uses legacy `generate_images_core()` wrapper
|
|
||||||
- Doesn't properly queue multiple images
|
|
||||||
|
|
||||||
**What We Need:**
|
|
||||||
- New function: `GenerateImagesFromPromptsFunction`
|
|
||||||
- Should work with `Images` model (which now has `content` relationship)
|
|
||||||
- Should process images in queue (one at a time)
|
|
||||||
- Should use progress modal similar to other AI functions
|
|
||||||
- Should use prompt templates and negative prompts from Thinker/Prompts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Architecture Overview
|
|
||||||
|
|
||||||
### 2.1 New Function: `GenerateImagesFromPromptsFunction`
|
|
||||||
|
|
||||||
**Purpose:** Generate actual images from existing image prompts stored in `Images` model
|
|
||||||
|
|
||||||
**Input:**
|
|
||||||
- `ids`: List of Image IDs (or Content IDs) to generate images for
|
|
||||||
- Images must have `prompt` field populated (from `GenerateImagePromptsFunction`)
|
|
||||||
|
|
||||||
**Output:**
|
|
||||||
- Updates `Images` records with:
|
|
||||||
- `image_url`: Generated image URL
|
|
||||||
- `status`: 'generated' (or 'failed' on error)
|
|
||||||
|
|
||||||
**Flow:**
|
|
||||||
1. **INIT (0-10%)**: Validate image IDs, check prompts exist
|
|
||||||
2. **PREP (10-25%)**: Load images, get settings, prepare queue
|
|
||||||
3. **AI_CALL (25-70%)**: Generate images sequentially (one per AI_CALL phase)
|
|
||||||
4. **PARSE (70-85%)**: Parse image URLs from responses
|
|
||||||
5. **SAVE (85-98%)**: Update Images records with URLs
|
|
||||||
6. **DONE (98-100%)**: Complete
|
|
||||||
|
|
||||||
### 2.2 Key Differences from Other Functions
|
|
||||||
|
|
||||||
**Unlike text generation functions:**
|
|
||||||
- **Multiple AI calls**: One AI call per image (not one call for all)
|
|
||||||
- **Sequential processing**: Images must be generated one at a time (rate limits)
|
|
||||||
- **Progress per image**: Need to track progress for each individual image
|
|
||||||
- **Different API**: Uses `AICore.generate_image()` instead of `AICore.run_ai_request()`
|
|
||||||
|
|
||||||
**Similarities:**
|
|
||||||
- Uses same `BaseAIFunction` pattern
|
|
||||||
- Uses same `AIEngine` orchestrator
|
|
||||||
- Uses same progress tracking system
|
|
||||||
- Uses same error handling
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Implementation Plan
|
|
||||||
|
|
||||||
### Phase 1: Backend AI Function
|
|
||||||
|
|
||||||
#### 3.1 Create `GenerateImagesFromPromptsFunction`
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/functions/generate_images_from_prompts.py`
|
|
||||||
|
|
||||||
**Class Structure:**
|
|
||||||
```python
|
|
||||||
class GenerateImagesFromPromptsFunction(BaseAIFunction):
|
|
||||||
def get_name(self) -> str:
|
|
||||||
return 'generate_images_from_prompts'
|
|
||||||
|
|
||||||
def get_metadata(self) -> Dict:
|
|
||||||
return {
|
|
||||||
'display_name': 'Generate Images from Prompts',
|
|
||||||
'description': 'Generate actual images from image prompts',
|
|
||||||
'phases': {
|
|
||||||
'INIT': 'Validating image prompts...',
|
|
||||||
'PREP': 'Preparing image generation queue...',
|
|
||||||
'AI_CALL': 'Generating images with AI...',
|
|
||||||
'PARSE': 'Processing image URLs...',
|
|
||||||
'SAVE': 'Saving image URLs...',
|
|
||||||
'DONE': 'Images generated!'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate(self, payload: dict, account=None) -> Dict:
|
|
||||||
"""Validate image IDs and check prompts exist"""
|
|
||||||
# Check for 'ids' array
|
|
||||||
# Check images exist and have prompts
|
|
||||||
# Check images have status='pending'
|
|
||||||
# Check account matches
|
|
||||||
|
|
||||||
def prepare(self, payload: dict, account=None) -> Dict:
|
|
||||||
"""Load images and settings"""
|
|
||||||
# Load Images records by IDs
|
|
||||||
# Get IntegrationSettings for image_generation
|
|
||||||
# Extract: provider, model, image_type, image_format, etc.
|
|
||||||
# Get prompt templates from PromptRegistry
|
|
||||||
# Return: {
|
|
||||||
# 'images': [Image objects],
|
|
||||||
# 'settings': {...},
|
|
||||||
# 'image_prompt_template': str,
|
|
||||||
# 'negative_prompt': str
|
|
||||||
# }
|
|
||||||
|
|
||||||
def build_prompt(self, data: Dict, account=None) -> Dict:
|
|
||||||
"""Format prompt using template"""
|
|
||||||
# For each image in queue:
|
|
||||||
# - Get content title (from image.content)
|
|
||||||
# - Format prompt using image_prompt_template
|
|
||||||
# - Return formatted prompt + image_type
|
|
||||||
# Note: This is called once per image (AIEngine handles iteration)
|
|
||||||
|
|
||||||
def parse_response(self, response: Dict, step_tracker=None) -> Dict:
|
|
||||||
"""Parse image URL from response"""
|
|
||||||
# Response from AICore.generate_image() has:
|
|
||||||
# - 'url': Image URL
|
|
||||||
# - 'revised_prompt': (optional)
|
|
||||||
# - 'cost': (optional)
|
|
||||||
# Return: {'url': str, 'revised_prompt': str, 'cost': float}
|
|
||||||
|
|
||||||
def save_output(self, parsed: Dict, original_data: Dict, account=None, ...) -> Dict:
|
|
||||||
"""Update Images record with URL"""
|
|
||||||
# Get image from original_data
|
|
||||||
# Update Images record:
|
|
||||||
# - image_url = parsed['url']
|
|
||||||
# - status = 'generated'
|
|
||||||
# - updated_at = now()
|
|
||||||
# Return: {'count': 1, 'images_generated': 1}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Implementation Details:**
|
|
||||||
|
|
||||||
1. **Multiple AI Calls Handling:**
|
|
||||||
- `AIEngine` will call `build_prompt()` → `AI_CALL` → `parse_response()` → `SAVE` for each image
|
|
||||||
- Need to track which image is being processed
|
|
||||||
- Use `step_tracker` to log progress per image
|
|
||||||
|
|
||||||
2. **Prompt Formatting:**
|
|
||||||
```python
|
|
||||||
# Get template from PromptRegistry
|
|
||||||
template = PromptRegistry.get_image_prompt_template(account)
|
|
||||||
|
|
||||||
# Format with content title and prompt
|
|
||||||
formatted = template.format(
|
|
||||||
post_title=image.content.title or image.content.meta_title,
|
|
||||||
image_prompt=image.prompt,
|
|
||||||
image_type=settings['image_type']
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Image Generation:**
|
|
||||||
```python
|
|
||||||
# Use AICore.generate_image()
|
|
||||||
result = ai_core.generate_image(
|
|
||||||
prompt=formatted_prompt,
|
|
||||||
provider=settings['provider'],
|
|
||||||
model=settings['model'],
|
|
||||||
size='1024x1024', # Default or from settings
|
|
||||||
negative_prompt=negative_prompt if provider == 'runware' else None,
|
|
||||||
function_name='generate_images_from_prompts'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Progress Tracking:**
|
|
||||||
- Track total images: `len(images)`
|
|
||||||
- Track completed: Increment after each SAVE
|
|
||||||
- Update progress: `(completed / total) * 100`
|
|
||||||
|
|
||||||
#### 3.2 Update AIEngine for Multiple AI Calls
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/engine.py`
|
|
||||||
|
|
||||||
**Changes Needed:**
|
|
||||||
- Detect if function needs multiple AI calls (check function name or metadata)
|
|
||||||
- For `generate_images_from_prompts`:
|
|
||||||
- Loop through images in PREP data
|
|
||||||
- For each image:
|
|
||||||
- Call `build_prompt()` with single image
|
|
||||||
- Call `AI_CALL` phase (generate image)
|
|
||||||
- Call `parse_response()`
|
|
||||||
- Call `SAVE` phase
|
|
||||||
- Update progress: `(current_image / total_images) * 100`
|
|
||||||
- After all images: Call DONE phase
|
|
||||||
|
|
||||||
**Alternative Approach (Simpler):**
|
|
||||||
- Process all images in `save_output()` method
|
|
||||||
- Make AI calls directly in `save_output()` (not through AIEngine phases)
|
|
||||||
- Update progress manually via `progress_tracker.update()`
|
|
||||||
- This is simpler but less consistent with framework
|
|
||||||
|
|
||||||
**Recommended Approach:**
|
|
||||||
- Use AIEngine's phase system
|
|
||||||
- Add metadata flag: `requires_multiple_ai_calls: True`
|
|
||||||
- AIEngine detects this and loops through items
|
|
||||||
|
|
||||||
#### 3.3 Register Function
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/registry.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _load_generate_images_from_prompts():
|
|
||||||
from igny8_core.ai.functions.generate_images_from_prompts import GenerateImagesFromPromptsFunction
|
|
||||||
return GenerateImagesFromPromptsFunction
|
|
||||||
|
|
||||||
register_lazy_function('generate_images_from_prompts', _load_generate_images_from_prompts)
|
|
||||||
```
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/functions/__init__.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
from .generate_images_from_prompts import GenerateImagesFromPromptsFunction
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
...
|
|
||||||
'GenerateImagesFromPromptsFunction',
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.4 Add Model Configuration
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/settings.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
MODEL_CONFIG = {
|
|
||||||
...
|
|
||||||
'generate_images_from_prompts': {
|
|
||||||
'model': 'dall-e-3', # Default, overridden by IntegrationSettings
|
|
||||||
'max_tokens': None, # Not used for images
|
|
||||||
'temperature': None, # Not used for images
|
|
||||||
'response_format': None, # Not used for images
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION_TO_PROMPT_TYPE = {
|
|
||||||
...
|
|
||||||
'generate_images_from_prompts': None, # Uses image_prompt_template, not text prompt
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.5 Update Progress Messages
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/ai/engine.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _get_prep_message(self, function_name: str, count: int, data: Any) -> str:
|
|
||||||
...
|
|
||||||
elif function_name == 'generate_images_from_prompts':
|
|
||||||
total_images = len(data.get('images', []))
|
|
||||||
return f"Preparing to generate {total_images} image{'s' if total_images != 1 else ''}"
|
|
||||||
|
|
||||||
def _get_ai_call_message(self, function_name: str, count: int) -> str:
|
|
||||||
...
|
|
||||||
elif function_name == 'generate_images_from_prompts':
|
|
||||||
return f"Generating image {count} of {total} with AI"
|
|
||||||
|
|
||||||
def _get_parse_message_with_count(self, function_name: str, count: int) -> str:
|
|
||||||
...
|
|
||||||
elif function_name == 'generate_images_from_prompts':
|
|
||||||
return f"{count} image{'s' if count != 1 else ''} generated"
|
|
||||||
|
|
||||||
def _get_save_message(self, function_name: str, count: int) -> str:
|
|
||||||
...
|
|
||||||
elif function_name == 'generate_images_from_prompts':
|
|
||||||
return f"Saving {count} image{'s' if count != 1 else ''}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Phase 2: API Endpoint
|
|
||||||
|
|
||||||
#### 3.6 Add API Endpoint
|
|
||||||
|
|
||||||
**File:** `backend/igny8_core/modules/writer/views.py`
|
|
||||||
|
|
||||||
**Add to `ImagesViewSet`:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
@action(detail=False, methods=['post'], url_path='generate_images', url_name='generate_images')
|
|
||||||
def generate_images(self, request):
|
|
||||||
"""Generate images from prompts for image records"""
|
|
||||||
from igny8_core.ai.tasks import run_ai_task
|
|
||||||
|
|
||||||
account = getattr(request, 'account', None)
|
|
||||||
ids = request.data.get('ids', [])
|
|
||||||
|
|
||||||
if not ids:
|
|
||||||
return Response({
|
|
||||||
'error': 'No IDs provided',
|
|
||||||
'type': 'ValidationError'
|
|
||||||
}, status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
account_id = account.id if account else None
|
|
||||||
|
|
||||||
# Queue Celery task
|
|
||||||
try:
|
|
||||||
if hasattr(run_ai_task, 'delay'):
|
|
||||||
task = run_ai_task.delay(
|
|
||||||
function_name='generate_images_from_prompts',
|
|
||||||
payload={'ids': ids},
|
|
||||||
account_id=account_id
|
|
||||||
)
|
|
||||||
return Response({
|
|
||||||
'success': True,
|
|
||||||
'task_id': str(task.id),
|
|
||||||
'message': 'Image generation started'
|
|
||||||
}, status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
# Fallback to synchronous execution
|
|
||||||
result = run_ai_task(
|
|
||||||
function_name='generate_images_from_prompts',
|
|
||||||
payload={'ids': ids},
|
|
||||||
account_id=account_id
|
|
||||||
)
|
|
||||||
if result.get('success'):
|
|
||||||
return Response({
|
|
||||||
'success': True,
|
|
||||||
'images_generated': result.get('count', 0),
|
|
||||||
'message': 'Images generated successfully'
|
|
||||||
}, status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return Response({
|
|
||||||
'error': result.get('error', 'Image generation failed'),
|
|
||||||
'type': 'TaskExecutionError'
|
|
||||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
except Exception as e:
|
|
||||||
return Response({
|
|
||||||
'error': str(e),
|
|
||||||
'type': 'ExecutionError'
|
|
||||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Phase 3: Frontend Integration
|
|
||||||
|
|
||||||
#### 3.7 Add API Function
|
|
||||||
|
|
||||||
**File:** `frontend/src/services/api.ts`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export async function generateImages(imageIds: number[]): Promise<any> {
|
|
||||||
return fetchAPI('/v1/writer/images/generate_images/', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ ids: imageIds }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.8 Add Generate Images Button
|
|
||||||
|
|
||||||
**File:** `frontend/src/config/pages/images.config.tsx`
|
|
||||||
|
|
||||||
**Add to row actions or status column:**
|
|
||||||
- Add "Generate Images" button in status column
|
|
||||||
- Only show if status is 'pending' and prompt exists
|
|
||||||
- Button should trigger generation for all images for that content
|
|
||||||
|
|
||||||
**File:** `frontend/src/pages/Writer/Images.tsx`
|
|
||||||
|
|
||||||
**Add handler:**
|
|
||||||
```typescript
|
|
||||||
const handleGenerateImages = useCallback(async (contentId: number) => {
|
|
||||||
try {
|
|
||||||
// Get all pending images for this content
|
|
||||||
const contentImages = images.find(g => g.content_id === contentId);
|
|
||||||
if (!contentImages) return;
|
|
||||||
|
|
||||||
// Collect all image IDs with prompts
|
|
||||||
const imageIds: number[] = [];
|
|
||||||
if (contentImages.featured_image?.id && contentImages.featured_image.status === 'pending') {
|
|
||||||
imageIds.push(contentImages.featured_image.id);
|
|
||||||
}
|
|
||||||
contentImages.in_article_images.forEach(img => {
|
|
||||||
if (img.id && img.status === 'pending' && img.prompt) {
|
|
||||||
imageIds.push(img.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (imageIds.length === 0) {
|
|
||||||
toast.info('No pending images with prompts found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await generateImages(imageIds);
|
|
||||||
if (result.success) {
|
|
||||||
if (result.task_id) {
|
|
||||||
// Open progress modal
|
|
||||||
progressModal.openModal(
|
|
||||||
result.task_id,
|
|
||||||
'Generate Images',
|
|
||||||
'ai-generate-images-from-prompts-01-desktop'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
toast.success(`Images generated: ${result.images_generated || 0} image${(result.images_generated || 0) === 1 ? '' : 's'} created`);
|
|
||||||
loadImages();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast.error(result.error || 'Failed to generate images');
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
toast.error(`Failed to generate images: ${error.message}`);
|
|
||||||
}
|
|
||||||
}, [toast, progressModal, loadImages, images]);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.9 Update Progress Modal
|
|
||||||
|
|
||||||
**File:** `frontend/src/components/common/ProgressModal.tsx`
|
|
||||||
|
|
||||||
**Add support for image generation:**
|
|
||||||
- Update step labels for `generate_images_from_prompts`
|
|
||||||
- Show progress per image
|
|
||||||
- Display generated images in modal (optional, like WP plugin)
|
|
||||||
|
|
||||||
**Step Labels:**
|
|
||||||
```typescript
|
|
||||||
if (funcName.includes('generate_images_from_prompts')) {
|
|
||||||
return [
|
|
||||||
{ phase: 'INIT', label: 'Validating image prompts' },
|
|
||||||
{ phase: 'PREP', label: 'Preparing image generation queue' },
|
|
||||||
{ phase: 'AI_CALL', label: 'Generating images with AI' },
|
|
||||||
{ phase: 'PARSE', label: 'Processing image URLs' },
|
|
||||||
{ phase: 'SAVE', label: 'Saving image URLs' },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Success Message:**
|
|
||||||
```typescript
|
|
||||||
if (funcName.includes('generate_images_from_prompts')) {
|
|
||||||
const imageCount = extractCount(/(\d+)\s+image/i, stepLogs || []);
|
|
||||||
if (imageCount) {
|
|
||||||
return `${imageCount} image${imageCount !== '1' ? 's' : ''} generated successfully`;
|
|
||||||
}
|
|
||||||
return 'Images generated successfully';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Technical Details
|
|
||||||
|
|
||||||
### 4.1 Image Generation API
|
|
||||||
|
|
||||||
**AICore.generate_image()** already exists and handles:
|
|
||||||
- OpenAI DALL-E (dall-e-2, dall-e-3)
|
|
||||||
- Runware API
|
|
||||||
- Negative prompts (Runware only)
|
|
||||||
- Cost tracking
|
|
||||||
- Error handling
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```python
|
|
||||||
result = ai_core.generate_image(
|
|
||||||
prompt=formatted_prompt,
|
|
||||||
provider='openai', # or 'runware'
|
|
||||||
model='dall-e-3', # or 'runware:97@1'
|
|
||||||
size='1024x1024',
|
|
||||||
negative_prompt=negative_prompt, # Only for Runware
|
|
||||||
function_name='generate_images_from_prompts'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```python
|
|
||||||
{
|
|
||||||
'url': 'https://...', # Image URL
|
|
||||||
'revised_prompt': '...', # OpenAI may revise prompt
|
|
||||||
'cost': 0.04, # Cost in USD
|
|
||||||
'error': None # Error message if failed
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.2 Settings Retrieval
|
|
||||||
|
|
||||||
**From IntegrationSettings:**
|
|
||||||
```python
|
|
||||||
integration = IntegrationSettings.objects.get(
|
|
||||||
account=account,
|
|
||||||
integration_type='image_generation',
|
|
||||||
is_active=True
|
|
||||||
)
|
|
||||||
config = integration.config
|
|
||||||
|
|
||||||
provider = config.get('provider') or config.get('service', 'openai')
|
|
||||||
if provider == 'runware':
|
|
||||||
model = config.get('model') or config.get('runwareModel', 'runware:97@1')
|
|
||||||
else:
|
|
||||||
model = config.get('model', 'dall-e-3')
|
|
||||||
|
|
||||||
image_type = config.get('image_type', 'realistic')
|
|
||||||
image_format = config.get('image_format', 'webp')
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.3 Prompt Templates
|
|
||||||
|
|
||||||
**From PromptRegistry:**
|
|
||||||
```python
|
|
||||||
image_prompt_template = PromptRegistry.get_image_prompt_template(account)
|
|
||||||
negative_prompt = PromptRegistry.get_negative_prompt(account)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Formatting:**
|
|
||||||
```python
|
|
||||||
formatted = image_prompt_template.format(
|
|
||||||
post_title=content.title or content.meta_title,
|
|
||||||
image_prompt=image.prompt,
|
|
||||||
image_type=image_type # 'realistic', 'artistic', 'cartoon'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.4 Error Handling
|
|
||||||
|
|
||||||
**Per-Image Errors:**
|
|
||||||
- If one image fails, continue with others
|
|
||||||
- Mark failed image: `status='failed'`
|
|
||||||
- Log error in `Images` record or separate error field
|
|
||||||
- Return success with partial count: `{'success': True, 'images_generated': 3, 'images_failed': 1}`
|
|
||||||
|
|
||||||
**Validation Errors:**
|
|
||||||
- No prompts: Skip image, log warning
|
|
||||||
- No settings: Return error, don't start generation
|
|
||||||
- Invalid provider/model: Return error
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Frontend Integration
|
|
||||||
|
|
||||||
### 5.1 Images Page Updates
|
|
||||||
|
|
||||||
**File:** `frontend/src/pages/Writer/Images.tsx`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. Add "Generate Images" button in status column (or row actions)
|
|
||||||
2. Button only enabled if:
|
|
||||||
- Status is 'pending'
|
|
||||||
- Prompt exists
|
|
||||||
- Content has at least one pending image
|
|
||||||
3. On click: Collect all pending image IDs for that content
|
|
||||||
4. Call API: `generateImages(imageIds)`
|
|
||||||
5. Open progress modal if async
|
|
||||||
6. Reload images on completion
|
|
||||||
|
|
||||||
### 5.2 Progress Modal Updates
|
|
||||||
|
|
||||||
**File:** `frontend/src/components/common/ProgressModal.tsx`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. Add step definitions for `generate_images_from_prompts`
|
|
||||||
2. Update progress messages
|
|
||||||
3. Show image count in messages
|
|
||||||
4. Optional: Display generated images in modal (like WP plugin)
|
|
||||||
|
|
||||||
### 5.3 Table Actions Config
|
|
||||||
|
|
||||||
**File:** `frontend/src/config/pages/table-actions.config.tsx`
|
|
||||||
|
|
||||||
**Add row action (optional):**
|
|
||||||
```typescript
|
|
||||||
'/writer/images': {
|
|
||||||
rowActions: [
|
|
||||||
{
|
|
||||||
key: 'generate_images',
|
|
||||||
label: 'Generate Images',
|
|
||||||
icon: <BoltIcon className="w-5 h-5" />,
|
|
||||||
variant: 'primary',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Testing Strategy
|
|
||||||
|
|
||||||
### 6.1 Unit Tests
|
|
||||||
|
|
||||||
**Test Function Methods:**
|
|
||||||
- `validate()`: Test with valid/invalid IDs, missing prompts, wrong status
|
|
||||||
- `prepare()`: Test settings retrieval, prompt template loading
|
|
||||||
- `build_prompt()`: Test prompt formatting
|
|
||||||
- `parse_response()`: Test URL extraction
|
|
||||||
- `save_output()`: Test Images record update
|
|
||||||
|
|
||||||
### 6.2 Integration Tests
|
|
||||||
|
|
||||||
**Test Full Flow:**
|
|
||||||
1. Create Images records with prompts
|
|
||||||
2. Call API endpoint
|
|
||||||
3. Verify Celery task created
|
|
||||||
4. Verify progress updates
|
|
||||||
5. Verify Images records updated with URLs
|
|
||||||
6. Verify status changed to 'generated'
|
|
||||||
|
|
||||||
### 6.3 Error Scenarios
|
|
||||||
|
|
||||||
**Test:**
|
|
||||||
- Missing IntegrationSettings
|
|
||||||
- Invalid provider/model
|
|
||||||
- API errors (rate limits, invalid API key)
|
|
||||||
- Partial failures (some images succeed, some fail)
|
|
||||||
- Missing prompts
|
|
||||||
- Invalid image IDs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Implementation Checklist
|
|
||||||
|
|
||||||
### Backend
|
|
||||||
- [ ] Create `GenerateImagesFromPromptsFunction` class
|
|
||||||
- [ ] Implement `validate()` method
|
|
||||||
- [ ] Implement `prepare()` method
|
|
||||||
- [ ] Implement `build_prompt()` method
|
|
||||||
- [ ] Implement `parse_response()` method
|
|
||||||
- [ ] Implement `save_output()` method
|
|
||||||
- [ ] Register function in `registry.py`
|
|
||||||
- [ ] Add to `__init__.py` exports
|
|
||||||
- [ ] Add model config in `settings.py`
|
|
||||||
- [ ] Update `AIEngine` progress messages
|
|
||||||
- [ ] Add API endpoint in `ImagesViewSet`
|
|
||||||
- [ ] Test with OpenAI provider
|
|
||||||
- [ ] Test with Runware provider
|
|
||||||
- [ ] Test error handling
|
|
||||||
|
|
||||||
### Frontend
|
|
||||||
- [ ] Add `generateImages()` API function
|
|
||||||
- [ ] Add "Generate Images" button to Images page
|
|
||||||
- [ ] Add click handler
|
|
||||||
- [ ] Integrate progress modal
|
|
||||||
- [ ] Update progress modal step labels
|
|
||||||
- [ ] Update success messages
|
|
||||||
- [ ] Test UI flow
|
|
||||||
- [ ] Test error handling
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
- [ ] Update AI_MASTER_ARCHITECTURE.md
|
|
||||||
- [ ] Add function to AI_FUNCTIONS_AUDIT_REPORT.md
|
|
||||||
- [ ] Document API endpoint
|
|
||||||
- [ ] Document settings requirements
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Key Considerations
|
|
||||||
|
|
||||||
### 8.1 Rate Limiting
|
|
||||||
|
|
||||||
**Issue:** Image generation APIs have rate limits
|
|
||||||
**Solution:** Process images sequentially (one at a time)
|
|
||||||
**Implementation:** AIEngine loops through images, waits for each to complete
|
|
||||||
|
|
||||||
### 8.2 Cost Tracking
|
|
||||||
|
|
||||||
**Issue:** Need to track costs per image
|
|
||||||
**Solution:** AICore already tracks costs, store in AITaskLog
|
|
||||||
**Implementation:** Cost is returned from `generate_image()`, log in step_tracker
|
|
||||||
|
|
||||||
### 8.3 Progress Updates
|
|
||||||
|
|
||||||
**Issue:** Need granular progress (per image)
|
|
||||||
**Solution:** Update progress after each image: `(completed / total) * 100`
|
|
||||||
**Implementation:** Track in `save_output()`, update via `progress_tracker.update()`
|
|
||||||
|
|
||||||
### 8.4 Error Recovery
|
|
||||||
|
|
||||||
**Issue:** If one image fails, should continue with others
|
|
||||||
**Solution:** Catch errors per image, mark as failed, continue
|
|
||||||
**Implementation:** Try-catch in `save_output()` per image
|
|
||||||
|
|
||||||
### 8.5 Image Display
|
|
||||||
|
|
||||||
**Issue:** Should show generated images in progress modal?
|
|
||||||
**Solution:** Optional enhancement, can add later
|
|
||||||
**Implementation:** Store image URLs in step logs, display in modal
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Alternative Approaches Considered
|
|
||||||
|
|
||||||
### 9.1 Process All in save_output()
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Simpler implementation
|
|
||||||
- Direct control over loop
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Doesn't use AIEngine phases properly
|
|
||||||
- Harder to track progress per image
|
|
||||||
- Less consistent with framework
|
|
||||||
|
|
||||||
**Decision:** Use AIEngine phases with loop detection
|
|
||||||
|
|
||||||
### 9.2 Separate Function Per Image
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Each image is independent task
|
|
||||||
- Better error isolation
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Too many Celery tasks
|
|
||||||
- Harder to track overall progress
|
|
||||||
- More complex frontend
|
|
||||||
|
|
||||||
**Decision:** Single function processes all images sequentially
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Success Criteria
|
|
||||||
|
|
||||||
✅ Function follows `BaseAIFunction` pattern
|
|
||||||
✅ Uses `AIEngine` orchestrator
|
|
||||||
✅ Integrates with progress modal
|
|
||||||
✅ Uses prompt templates from Thinker/Prompts
|
|
||||||
✅ Uses settings from IntegrationSettings
|
|
||||||
✅ Handles errors gracefully
|
|
||||||
✅ Tracks progress per image
|
|
||||||
✅ Updates Images records correctly
|
|
||||||
✅ Works with both OpenAI and Runware
|
|
||||||
✅ Frontend button triggers generation
|
|
||||||
✅ Progress modal shows correct steps
|
|
||||||
✅ Success message shows image count
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. Next Steps
|
|
||||||
|
|
||||||
1. **Start with Backend Function**
|
|
||||||
- Create `GenerateImagesFromPromptsFunction`
|
|
||||||
- Implement all methods
|
|
||||||
- Test with single image
|
|
||||||
|
|
||||||
2. **Add API Endpoint**
|
|
||||||
- Add to `ImagesViewSet`
|
|
||||||
- Test endpoint
|
|
||||||
|
|
||||||
3. **Frontend Integration**
|
|
||||||
- Add button
|
|
||||||
- Add handler
|
|
||||||
- Test flow
|
|
||||||
|
|
||||||
4. **Progress Modal**
|
|
||||||
- Update step labels
|
|
||||||
- Test progress updates
|
|
||||||
|
|
||||||
5. **Error Handling**
|
|
||||||
- Test error scenarios
|
|
||||||
- Verify graceful failures
|
|
||||||
|
|
||||||
6. **Documentation**
|
|
||||||
- Update architecture docs
|
|
||||||
- Add API docs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**End of Plan**
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
146
docs/README.md
Normal file
146
docs/README.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# IGNY8 Documentation
|
||||||
|
|
||||||
|
**Last Updated:** 2025-01-XX
|
||||||
|
**Purpose:** Complete documentation index for the IGNY8 platform.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation Structure
|
||||||
|
|
||||||
|
All documentation is organized in this single folder with the following structure:
|
||||||
|
|
||||||
|
### Core Documentation
|
||||||
|
|
||||||
|
1. **[01-ARCHITECTURE-TECH-STACK.md](./01-ARCHITECTURE-TECH-STACK.md)**
|
||||||
|
- Technology stack overview
|
||||||
|
- System architecture principles
|
||||||
|
- Infrastructure components
|
||||||
|
- External service integrations
|
||||||
|
|
||||||
|
2. **[02-APP-ARCHITECTURE.md](./02-APP-ARCHITECTURE.md)**
|
||||||
|
- IGNY8 application architecture
|
||||||
|
- System hierarchy and relationships
|
||||||
|
- Module organization
|
||||||
|
- Complete workflows
|
||||||
|
- Data flow and processing
|
||||||
|
- Multi-tenancy architecture
|
||||||
|
- Security architecture
|
||||||
|
|
||||||
|
3. **[03-FRONTEND.md](./03-FRONTEND.md)**
|
||||||
|
- Frontend architecture
|
||||||
|
- Project structure
|
||||||
|
- Routing system
|
||||||
|
- Template system
|
||||||
|
- Component library
|
||||||
|
- State management
|
||||||
|
- API integration
|
||||||
|
- Configuration system
|
||||||
|
- All pages and features
|
||||||
|
|
||||||
|
4. **[04-BACKEND.md](./04-BACKEND.md)**
|
||||||
|
- Backend architecture
|
||||||
|
- Project structure
|
||||||
|
- Models and relationships
|
||||||
|
- ViewSets and API endpoints
|
||||||
|
- Serializers
|
||||||
|
- Celery tasks
|
||||||
|
- Middleware
|
||||||
|
- All modules (Planner, Writer, System, Billing, Auth)
|
||||||
|
|
||||||
|
5. **[05-AI-FUNCTIONS.md](./05-AI-FUNCTIONS.md)**
|
||||||
|
- AI framework architecture
|
||||||
|
- All 5 AI functions (complete details)
|
||||||
|
- AI function execution flow
|
||||||
|
- Prompt management
|
||||||
|
- Model configuration
|
||||||
|
- Progress tracking
|
||||||
|
- Cost tracking
|
||||||
|
|
||||||
|
6. **[06-CHANGELOG.md](./06-CHANGELOG.md)**
|
||||||
|
- System changelog
|
||||||
|
- Feature additions
|
||||||
|
- Updates and improvements
|
||||||
|
- Version history
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
1. **New to IGNY8?** Start with [01-ARCHITECTURE-TECH-STACK.md](./01-ARCHITECTURE-TECH-STACK.md) for technology overview
|
||||||
|
2. **Understanding the System?** Read [02-APP-ARCHITECTURE.md](./02-APP-ARCHITECTURE.md) for complete architecture
|
||||||
|
3. **Frontend Development?** See [03-FRONTEND.md](./03-FRONTEND.md) for all frontend details
|
||||||
|
4. **Backend Development?** See [04-BACKEND.md](./04-BACKEND.md) for all backend details
|
||||||
|
5. **Working with AI?** See [05-AI-FUNCTIONS.md](./05-AI-FUNCTIONS.md) for AI functions
|
||||||
|
6. **What's New?** Check [06-CHANGELOG.md](./06-CHANGELOG.md) for recent changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Documentation Overview
|
||||||
|
|
||||||
|
### System Capabilities
|
||||||
|
|
||||||
|
- **Multi-Tenancy**: Complete account isolation with automatic filtering
|
||||||
|
- **Planner Module**: Keywords, Clusters, Content Ideas management
|
||||||
|
- **Writer Module**: Tasks, Content, Images generation and management
|
||||||
|
- **Thinker Module**: Prompts, Author Profiles, Strategies, Image Testing
|
||||||
|
- **System Module**: Settings, Integrations, AI Prompts
|
||||||
|
- **Billing Module**: Credits, Transactions, Usage Logs
|
||||||
|
- **AI Functions**: 5 AI operations (Auto Cluster, Generate Ideas, Generate Content, Generate Image Prompts, Generate Images)
|
||||||
|
|
||||||
|
### Technology Stack
|
||||||
|
|
||||||
|
- **Backend**: Django 5.2+ with Django REST Framework
|
||||||
|
- **Frontend**: React 19 with TypeScript and Vite
|
||||||
|
- **Database**: PostgreSQL 15
|
||||||
|
- **Task Queue**: Celery with Redis
|
||||||
|
- **Deployment**: Docker-based containerization
|
||||||
|
- **Reverse Proxy**: Caddy (HTTPS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Finding Information
|
||||||
|
|
||||||
|
### By Topic
|
||||||
|
|
||||||
|
- **Architecture & Design**: [01-ARCHITECTURE-TECH-STACK.md](./01-ARCHITECTURE-TECH-STACK.md), [02-APP-ARCHITECTURE.md](./02-APP-ARCHITECTURE.md)
|
||||||
|
- **Frontend Development**: [03-FRONTEND.md](./03-FRONTEND.md)
|
||||||
|
- **Backend Development**: [04-BACKEND.md](./04-BACKEND.md)
|
||||||
|
- **AI Functions**: [05-AI-FUNCTIONS.md](./05-AI-FUNCTIONS.md)
|
||||||
|
- **Changes & Updates**: [06-CHANGELOG.md](./06-CHANGELOG.md)
|
||||||
|
|
||||||
|
### By Module
|
||||||
|
|
||||||
|
- **Planner**: See [02-APP-ARCHITECTURE.md](./02-APP-ARCHITECTURE.md) (Module Organization) and [04-BACKEND.md](./04-BACKEND.md) (Planner Module)
|
||||||
|
- **Writer**: See [02-APP-ARCHITECTURE.md](./02-APP-ARCHITECTURE.md) (Module Organization) and [04-BACKEND.md](./04-BACKEND.md) (Writer Module)
|
||||||
|
- **Thinker**: See [03-FRONTEND.md](./03-FRONTEND.md) (Thinker Pages) and [04-BACKEND.md](./04-BACKEND.md) (System Module)
|
||||||
|
- **System**: See [04-BACKEND.md](./04-BACKEND.md) (System Module)
|
||||||
|
- **Billing**: See [04-BACKEND.md](./04-BACKEND.md) (Billing Module)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Documentation Standards
|
||||||
|
|
||||||
|
- **No Code**: Documentation focuses on workflows, features, and architecture (no code snippets)
|
||||||
|
- **Complete**: All workflows and features are documented
|
||||||
|
- **Accurate**: Documentation reflects current system state
|
||||||
|
- **Detailed**: Comprehensive coverage of all aspects
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Keeping Documentation Updated
|
||||||
|
|
||||||
|
Documentation is updated when:
|
||||||
|
- New features are added
|
||||||
|
- Workflows change
|
||||||
|
- Architecture evolves
|
||||||
|
- Modules are modified
|
||||||
|
|
||||||
|
**Last Review**: 2025-01-XX
|
||||||
|
**Next Review**: As system evolves
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
For questions or clarifications about the documentation, refer to the specific document or contact the development team.
|
||||||
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
# AI Folder Files Analysis
|
|
||||||
## Which Files Are Actually Needed for 3 Active Functions
|
|
||||||
|
|
||||||
### ✅ **REQUIRED FILES** (All needed for active functions)
|
|
||||||
|
|
||||||
#### 1. **tasks.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Unified Celery task entrypoint
|
|
||||||
- **Used by:** All views (planner/views.py, writer/views.py)
|
|
||||||
- **Dependencies:** engine.py, registry.py
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 2. **engine.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Central orchestrator for all AI functions
|
|
||||||
- **Used by:** tasks.py
|
|
||||||
- **Dependencies:** base.py, tracker.py, ai_core.py, settings.py, models.py
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 3. **base.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Abstract base class for all AI functions
|
|
||||||
- **Used by:** All function classes (AutoClusterFunction, GenerateIdeasFunction, GenerateContentFunction)
|
|
||||||
- **Dependencies:** None
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 4. **registry.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Function registry with lazy loading
|
|
||||||
- **Used by:** tasks.py
|
|
||||||
- **Dependencies:** base.py, function modules
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 5. **ai_core.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Centralized AI request handler
|
|
||||||
- **Used by:** engine.py, all function classes
|
|
||||||
- **Dependencies:** constants.py, tracker.py
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 6. **prompts.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Centralized prompt management
|
|
||||||
- **Used by:** All function classes (build_prompt methods)
|
|
||||||
- **Dependencies:** None
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 7. **settings.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Model configurations per function
|
|
||||||
- **Used by:** engine.py
|
|
||||||
- **Dependencies:** constants.py (via ai_processor import)
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 8. **validators.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Validation functions
|
|
||||||
- **Used by:** All function classes (validate methods)
|
|
||||||
- **Dependencies:** constants.py, models
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 9. **tracker.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Progress tracking utilities
|
|
||||||
- **Used by:** engine.py, ai_core.py
|
|
||||||
- **Dependencies:** types.py (imported but NOT USED), constants.py
|
|
||||||
- **Status:** KEEP (but can remove types.py import)
|
|
||||||
|
|
||||||
#### 10. **constants.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** AI constants (model rates, valid models)
|
|
||||||
- **Used by:** ai_core.py, settings.py, validators.py
|
|
||||||
- **Dependencies:** None
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 11. **models.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** AITaskLog database model
|
|
||||||
- **Used by:** engine.py (for logging), admin.py
|
|
||||||
- **Dependencies:** AccountBaseModel
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 12. **apps.py** - ✅ REQUIRED
|
|
||||||
- **Purpose:** Django app configuration
|
|
||||||
- **Used by:** Django (app registration)
|
|
||||||
- **Dependencies:** admin.py
|
|
||||||
- **Status:** KEEP
|
|
||||||
|
|
||||||
#### 13. **admin.py** - ✅ REQUIRED (Optional but recommended)
|
|
||||||
- **Purpose:** Django admin interface for AITaskLog
|
|
||||||
- **Used by:** apps.py (auto-imported)
|
|
||||||
- **Dependencies:** models.py
|
|
||||||
- **Status:** KEEP (useful for debugging/admin)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### ❌ **UNUSED FILES** (Can be removed)
|
|
||||||
|
|
||||||
#### 1. **types.py** - ❌ NOT USED
|
|
||||||
- **Purpose:** Type definitions (StepLog, ProgressState, AITaskResult dataclasses)
|
|
||||||
- **Used by:** tracker.py (imported but never instantiated)
|
|
||||||
- **Actual usage:** None - tracker.py uses plain Dict types instead
|
|
||||||
- **Status:** **SAFE TO REMOVE**
|
|
||||||
- **Action:** Remove file and remove import from tracker.py
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Files to KEEP (13 files):
|
|
||||||
1. ✅ tasks.py
|
|
||||||
2. ✅ engine.py
|
|
||||||
3. ✅ base.py
|
|
||||||
4. ✅ registry.py
|
|
||||||
5. ✅ ai_core.py
|
|
||||||
6. ✅ prompts.py
|
|
||||||
7. ✅ settings.py
|
|
||||||
8. ✅ validators.py
|
|
||||||
9. ✅ tracker.py
|
|
||||||
10. ✅ constants.py
|
|
||||||
11. ✅ models.py
|
|
||||||
12. ✅ apps.py
|
|
||||||
13. ✅ admin.py
|
|
||||||
|
|
||||||
### Files to REMOVE (1 file):
|
|
||||||
1. ❌ **types.py** - Imported but never used
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Action Items
|
|
||||||
|
|
||||||
1. **Remove types.py** - File is not used
|
|
||||||
2. **Remove import from tracker.py** - Remove `from igny8_core.ai.types import StepLog, ProgressState` (line 8)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
All other files are actively used in the execution flow:
|
|
||||||
- **tasks.py** → **registry.py** → **engine.py** → **base.py** (function classes)
|
|
||||||
- **engine.py** → **ai_core.py** → **constants.py**
|
|
||||||
- **engine.py** → **tracker.py** → **constants.py**
|
|
||||||
- **engine.py** → **settings.py** → **constants.py**
|
|
||||||
- **engine.py** → **models.py** (AITaskLog)
|
|
||||||
- **function classes** → **prompts.py**, **validators.py**
|
|
||||||
- **apps.py** → **admin.py** → **models.py**
|
|
||||||
|
|
||||||
1
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
# AI Functions Deep Audit Report
|
|
||||||
## Clustering, Idea Generation, and Content Generation
|
|
||||||
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Scope:** Complete audit of AI functions for clustering, idea generation, and content generation to identify unused code and files safe to remove.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
This audit identifies **legacy code, deprecated functions, and unused implementations** that are safe to remove from the codebase. The current system uses a unified AI framework through `run_ai_task` → `AIEngine` → `BaseAIFunction` implementations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. CURRENT ACTIVE ARCHITECTURE
|
|
||||||
|
|
||||||
### 1.1 Active Flow (What's Actually Used)
|
|
||||||
|
|
||||||
```
|
|
||||||
Frontend API Call
|
|
||||||
↓
|
|
||||||
views.py (auto_cluster/auto_generate_ideas/auto_generate_content)
|
|
||||||
↓
|
|
||||||
run_ai_task (ai/tasks.py) - Unified Celery task entrypoint
|
|
||||||
↓
|
|
||||||
AIEngine (ai/engine.py) - Orchestrator
|
|
||||||
↓
|
|
||||||
BaseAIFunction implementations:
|
|
||||||
- AutoClusterFunction (ai/functions/auto_cluster.py)
|
|
||||||
- GenerateIdeasFunction (ai/functions/generate_ideas.py)
|
|
||||||
- GenerateContentFunction (ai/functions/generate_content.py)
|
|
||||||
↓
|
|
||||||
AICore (ai/ai_core.py) - Centralized AI request handler
|
|
||||||
↓
|
|
||||||
AIProvider (OpenAI/Runware)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 1.2 Active Files (KEEP)
|
|
||||||
|
|
||||||
#### Core Framework
|
|
||||||
- ✅ `backend/igny8_core/ai/tasks.py` - Unified Celery task (`run_ai_task`)
|
|
||||||
- ✅ `backend/igny8_core/ai/engine.py` - AIEngine orchestrator
|
|
||||||
- ✅ `backend/igny8_core/ai/base.py` - BaseAIFunction abstract class
|
|
||||||
- ✅ `backend/igny8_core/ai/ai_core.py` - AICore centralized handler
|
|
||||||
- ✅ `backend/igny8_core/ai/registry.py` - Function registry
|
|
||||||
- ✅ `backend/igny8_core/ai/prompts.py` - PromptRegistry
|
|
||||||
- ✅ `backend/igny8_core/ai/settings.py` - Model configurations
|
|
||||||
- ✅ `backend/igny8_core/ai/constants.py` - AI constants
|
|
||||||
- ✅ `backend/igny8_core/ai/tracker.py` - Progress tracking
|
|
||||||
- ✅ `backend/igny8_core/ai/validators.py` - Validation functions
|
|
||||||
|
|
||||||
#### Function Implementations
|
|
||||||
- ✅ `backend/igny8_core/ai/functions/auto_cluster.py` - AutoClusterFunction
|
|
||||||
- ✅ `backend/igny8_core/ai/functions/generate_ideas.py` - GenerateIdeasFunction
|
|
||||||
- ✅ `backend/igny8_core/ai/functions/generate_content.py` - GenerateContentFunction
|
|
||||||
- ✅ `backend/igny8_core/ai/functions/__init__.py` - Exports
|
|
||||||
|
|
||||||
#### API Endpoints
|
|
||||||
- ✅ `backend/igny8_core/modules/planner/views.py` - KeywordViewSet.auto_cluster(), ClusterViewSet.auto_generate_ideas()
|
|
||||||
- ✅ `backend/igny8_core/modules/writer/views.py` - TasksViewSet.auto_generate_content()
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. DEPRECATED / UNUSED CODE (SAFE TO REMOVE)
|
|
||||||
|
|
||||||
### 2.1 Legacy Wrapper Functions (NOT USED)
|
|
||||||
|
|
||||||
#### ❌ `generate_ideas_core()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/ai/functions/generate_ideas.py:234`
|
|
||||||
- **Status:** Legacy wrapper function for backward compatibility
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE** (only in commented test code)
|
|
||||||
- **Purpose:** Was meant for direct calls without Celery, but all calls now go through `run_ai_task`
|
|
||||||
- **Action:** **REMOVE** - Function and export from `__init__.py`
|
|
||||||
|
|
||||||
#### ❌ `generate_content_core()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/ai/functions/generate_content.py:303`
|
|
||||||
- **Status:** Legacy wrapper function for backward compatibility
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE** (only in commented test code)
|
|
||||||
- **Purpose:** Was meant for direct calls without Celery, but all calls now go through `run_ai_task`
|
|
||||||
- **Action:** **REMOVE** - Function and export from `__init__.py`
|
|
||||||
|
|
||||||
### 2.2 AIProcessor Deprecated Methods (NOT USED)
|
|
||||||
|
|
||||||
#### ❌ `AIProcessor.cluster_keywords()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/utils/ai_processor.py:1049-1282`
|
|
||||||
- **Status:** ⚠️ **DEPRECATED** (marked with deprecation warning)
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE**
|
|
||||||
- **Lines:** ~233 lines of code
|
|
||||||
- **Action:** **REMOVE** entire method
|
|
||||||
|
|
||||||
#### ❌ `AIProcessor.generate_ideas()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/utils/ai_processor.py:1284-1363`
|
|
||||||
- **Status:** Legacy method
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE**
|
|
||||||
- **Lines:** ~80 lines of code
|
|
||||||
- **Action:** **REMOVE** entire method
|
|
||||||
|
|
||||||
#### ❌ `AIProcessor.generate_content()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/utils/ai_processor.py:433-531`
|
|
||||||
- **Status:** Legacy method
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE** (only called internally by `extract_image_prompts`, which is also unused)
|
|
||||||
- **Lines:** ~98 lines of code
|
|
||||||
- **Action:** **REMOVE** entire method
|
|
||||||
|
|
||||||
#### ❌ `AIProcessor.extract_image_prompts()` - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/utils/ai_processor.py:471-580`
|
|
||||||
- **Status:** Legacy method
|
|
||||||
- **Usage:** ❌ **NOT CALLED ANYWHERE** (new framework uses `GenerateImagesFunction` which uses `AICore.run_ai_request` directly)
|
|
||||||
- **Lines:** ~110 lines of code
|
|
||||||
- **Action:** **REMOVE** entire method
|
|
||||||
|
|
||||||
**Note:** `AIProcessor.generate_image()` is **STILL USED** in `integration_views.py` for image generation, so keep the class and that method.
|
|
||||||
|
|
||||||
### 2.3 Unused Exports
|
|
||||||
|
|
||||||
#### ❌ `generate_ideas_core` export - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/ai/functions/__init__.py:5,12`
|
|
||||||
- **Action:** Remove from imports and `__all__`
|
|
||||||
|
|
||||||
#### ❌ `generate_content_core` export - **SAFE TO REMOVE**
|
|
||||||
- **Location:** `backend/igny8_core/ai/functions/__init__.py:6,14`
|
|
||||||
- **Action:** Remove from imports and `__all__`
|
|
||||||
|
|
||||||
### 2.4 Test File Cleanup
|
|
||||||
|
|
||||||
#### ⚠️ `backend/igny8_core/ai/tests/test_run.py`
|
|
||||||
- **Status:** Contains commented-out code referencing removed functions
|
|
||||||
- **Action:** Clean up commented code (lines 16, 63, 75, 126-127)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. AIProcessor - PARTIAL CLEANUP
|
|
||||||
|
|
||||||
### 3.1 What to KEEP in AIProcessor
|
|
||||||
|
|
||||||
✅ **KEEP:**
|
|
||||||
- `AIProcessor.__init__()` - Initialization
|
|
||||||
- `AIProcessor._get_api_key()` - API key retrieval
|
|
||||||
- `AIProcessor._get_model()` - Model retrieval
|
|
||||||
- `AIProcessor._call_openai()` - OpenAI API calls (used by generate_image)
|
|
||||||
- `AIProcessor._extract_json_from_response()` - JSON extraction
|
|
||||||
- `AIProcessor.generate_image()` - **STILL USED** in `integration_views.py`
|
|
||||||
- `AIProcessor.get_prompt()` - May be used by generate_image
|
|
||||||
- Constants imports (MODEL_RATES, etc.) - Used by AICore
|
|
||||||
|
|
||||||
### 3.2 What to REMOVE from AIProcessor
|
|
||||||
|
|
||||||
❌ **REMOVE:**
|
|
||||||
- `AIProcessor.cluster_keywords()` - ~233 lines
|
|
||||||
- `AIProcessor.generate_ideas()` - ~80 lines
|
|
||||||
- `AIProcessor.generate_content()` - ~98 lines
|
|
||||||
- `AIProcessor.extract_image_prompts()` - ~110 lines
|
|
||||||
- **Total:** ~521 lines of unused code
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. FILES ALREADY DELETED (Good!)
|
|
||||||
|
|
||||||
✅ **Already Removed:**
|
|
||||||
- `backend/igny8_core/modules/planner/tasks.py` - ✅ Already deleted
|
|
||||||
- `backend/igny8_core/modules/writer/tasks.py` - ✅ Already deleted
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. SUMMARY OF REMOVALS
|
|
||||||
|
|
||||||
### 5.1 Functions to Remove
|
|
||||||
|
|
||||||
| Function | Location | Lines | Status |
|
|
||||||
|----------|----------|-------|--------|
|
|
||||||
| `generate_ideas_core()` | `ai/functions/generate_ideas.py:234` | ~100 | ❌ Remove |
|
|
||||||
| `generate_content_core()` | `ai/functions/generate_content.py:303` | ~85 | ❌ Remove |
|
|
||||||
| `AIProcessor.cluster_keywords()` | `utils/ai_processor.py:1049` | ~233 | ❌ Remove |
|
|
||||||
| `AIProcessor.generate_ideas()` | `utils/ai_processor.py:1284` | ~80 | ❌ Remove |
|
|
||||||
| `AIProcessor.generate_content()` | `utils/ai_processor.py:433` | ~98 | ❌ Remove |
|
|
||||||
| `AIProcessor.extract_image_prompts()` | `utils/ai_processor.py:471` | ~110 | ❌ Remove |
|
|
||||||
|
|
||||||
**Total Lines to Remove:** ~706 lines
|
|
||||||
|
|
||||||
### 5.2 Exports to Remove
|
|
||||||
|
|
||||||
| Export | Location |
|
|
||||||
|--------|----------|
|
|
||||||
| `generate_ideas_core` | `ai/functions/__init__.py:5,12` |
|
|
||||||
| `generate_content_core` | `ai/functions/__init__.py:6,14` |
|
|
||||||
|
|
||||||
### 5.3 Test Cleanup
|
|
||||||
|
|
||||||
| File | Action |
|
|
||||||
|------|--------|
|
|
||||||
| `ai/tests/test_run.py` | Remove commented code (lines 16, 63, 75, 126-127) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. VERIFICATION CHECKLIST
|
|
||||||
|
|
||||||
Before removing, verify:
|
|
||||||
|
|
||||||
- [ ] ✅ No imports of `generate_ideas_core` or `generate_content_core` anywhere
|
|
||||||
- [ ] ✅ No calls to `AIProcessor.cluster_keywords()`, `generate_ideas()`, or `generate_content()`
|
|
||||||
- [ ] ✅ All active code paths use `run_ai_task` → `AIEngine` → `BaseAIFunction`
|
|
||||||
- [ ] ✅ `AIProcessor.generate_image()` is still used (verify in `integration_views.py`)
|
|
||||||
- [ ] ✅ Constants from `ai_processor.py` are still imported by `AICore` (verify)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. RECOMMENDED REMOVAL ORDER
|
|
||||||
|
|
||||||
1. **Phase 1: Remove Legacy Wrapper Functions**
|
|
||||||
- Remove `generate_ideas_core()` from `generate_ideas.py`
|
|
||||||
- Remove `generate_content_core()` from `generate_content.py`
|
|
||||||
- Remove exports from `__init__.py`
|
|
||||||
|
|
||||||
2. **Phase 2: Remove AIProcessor Deprecated Methods**
|
|
||||||
- Remove `AIProcessor.cluster_keywords()`
|
|
||||||
- Remove `AIProcessor.generate_ideas()`
|
|
||||||
- Remove `AIProcessor.generate_content()`
|
|
||||||
- Remove `AIProcessor.extract_image_prompts()` (depends on generate_content, so remove after)
|
|
||||||
|
|
||||||
3. **Phase 3: Cleanup Tests**
|
|
||||||
- Clean up commented code in `test_run.py`
|
|
||||||
|
|
||||||
4. **Phase 4: Verification**
|
|
||||||
- Run full test suite
|
|
||||||
- Verify all AI functions still work
|
|
||||||
- Check for any broken imports
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. IMPACT ANALYSIS
|
|
||||||
|
|
||||||
### 8.1 No Breaking Changes Expected
|
|
||||||
|
|
||||||
- ✅ All active code paths use the new framework
|
|
||||||
- ✅ No external dependencies on removed functions
|
|
||||||
- ✅ Views only use `run_ai_task` (verified)
|
|
||||||
|
|
||||||
### 8.2 Benefits
|
|
||||||
|
|
||||||
- 🎯 **~706 lines of dead code removed**
|
|
||||||
- 🎯 **Clearer codebase** - Only active code remains
|
|
||||||
- 🎯 **Easier maintenance** - No confusion about which path to use
|
|
||||||
- 🎯 **Reduced technical debt**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. FILES TO MODIFY
|
|
||||||
|
|
||||||
### 9.1 Files to Edit
|
|
||||||
|
|
||||||
1. `backend/igny8_core/ai/functions/generate_ideas.py`
|
|
||||||
- Remove `generate_ideas_core()` function (lines 234-333)
|
|
||||||
|
|
||||||
2. `backend/igny8_core/ai/functions/generate_content.py`
|
|
||||||
- Remove `generate_content_core()` function (lines 303-386)
|
|
||||||
|
|
||||||
3. `backend/igny8_core/ai/functions/__init__.py`
|
|
||||||
- Remove `generate_ideas_core` import and export
|
|
||||||
- Remove `generate_content_core` import and export
|
|
||||||
|
|
||||||
4. `backend/igny8_core/utils/ai_processor.py`
|
|
||||||
- Remove `cluster_keywords()` method (lines 1049-1282)
|
|
||||||
- Remove `generate_ideas()` method (lines 1284-1363)
|
|
||||||
- Remove `generate_content()` method (lines 433-531)
|
|
||||||
- Remove `extract_image_prompts()` method (lines 471-580)
|
|
||||||
|
|
||||||
5. `backend/igny8_core/ai/tests/test_run.py`
|
|
||||||
- Remove commented code referencing removed functions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. CONCLUSION
|
|
||||||
|
|
||||||
This audit identifies **~706 lines of unused legacy code** that can be safely removed without impacting functionality. All active code paths use the unified AI framework (`run_ai_task` → `AIEngine` → `BaseAIFunction`), making these legacy functions obsolete.
|
|
||||||
|
|
||||||
**Recommendation:** Proceed with removal in phases as outlined above, with thorough testing after each phase.
|
|
||||||
|
|
||||||
@@ -1,802 +0,0 @@
|
|||||||
# AI Master Architecture Document
|
|
||||||
## Clustering, Idea Generation, and Content Generation
|
|
||||||
|
|
||||||
**Version:** 1.0
|
|
||||||
**Date:** 2025-01-XX
|
|
||||||
**Scope:** Complete architecture for 3 verified AI functions (clustering, idea generation, content generation)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Common Architecture](#1-common-architecture)
|
|
||||||
2. [Auto Cluster Keywords](#2-auto-cluster-keywords)
|
|
||||||
3. [Generate Ideas](#3-generate-ideas)
|
|
||||||
4. [Generate Content](#4-generate-content)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Common Architecture
|
|
||||||
|
|
||||||
### 1.1 Core Framework Files
|
|
||||||
|
|
||||||
#### Entry Point
|
|
||||||
- **File:** `backend/igny8_core/ai/tasks.py`
|
|
||||||
- **Function:** `run_ai_task`
|
|
||||||
- **Purpose:** Unified Celery task entrypoint for all AI functions
|
|
||||||
- **Parameters:** `function_name` (str), `payload` (dict), `account_id` (int)
|
|
||||||
- **Flow:** Loads function from registry → Creates AIEngine → Executes function
|
|
||||||
|
|
||||||
#### Engine Orchestrator
|
|
||||||
- **File:** `backend/igny8_core/ai/engine.py`
|
|
||||||
- **Class:** `AIEngine`
|
|
||||||
- **Purpose:** Central orchestrator managing lifecycle, progress, logging, cost tracking
|
|
||||||
- **Methods:**
|
|
||||||
- `execute` - Main execution pipeline (6 phases: INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
|
||||||
- `_handle_error` - Centralized error handling
|
|
||||||
- `_log_to_database` - Logs to AITaskLog model
|
|
||||||
- Helper methods: `_get_input_description`, `_build_validation_message`, `_get_prep_message`, `_get_ai_call_message`, `_get_parse_message`, `_get_parse_message_with_count`, `_get_save_message`, `_calculate_credits_for_clustering`
|
|
||||||
|
|
||||||
#### Base Function Class
|
|
||||||
- **File:** `backend/igny8_core/ai/base.py`
|
|
||||||
- **Class:** `BaseAIFunction`
|
|
||||||
- **Purpose:** Abstract base class defining interface for all AI functions
|
|
||||||
- **Abstract Methods:**
|
|
||||||
- `get_name` - Returns function name (e.g., 'auto_cluster')
|
|
||||||
- `prepare` - Loads and prepares data
|
|
||||||
- `build_prompt` - Builds AI prompt
|
|
||||||
- `parse_response` - Parses AI response
|
|
||||||
- `save_output` - Saves results to database
|
|
||||||
- **Optional Methods:**
|
|
||||||
- `get_metadata` - Returns display name, description, phases
|
|
||||||
- `get_max_items` - Returns max items limit (or None)
|
|
||||||
- `validate` - Validates input payload (default: checks for 'ids')
|
|
||||||
- `get_model` - Returns model override (default: None, uses account default)
|
|
||||||
|
|
||||||
#### Function Registry
|
|
||||||
- **File:** `backend/igny8_core/ai/registry.py`
|
|
||||||
- **Functions:**
|
|
||||||
- `register_function` - Registers function class
|
|
||||||
- `register_lazy_function` - Registers lazy loader
|
|
||||||
- `get_function` - Gets function class by name (lazy loads if needed)
|
|
||||||
- `get_function_instance` - Gets function instance by name
|
|
||||||
- `list_functions` - Lists all registered functions
|
|
||||||
- **Lazy Loaders:**
|
|
||||||
- `_load_auto_cluster` - Loads AutoClusterFunction
|
|
||||||
- `_load_generate_ideas` - Loads GenerateIdeasFunction
|
|
||||||
- `_load_generate_content` - Loads GenerateContentFunction
|
|
||||||
|
|
||||||
#### AI Core Handler
|
|
||||||
- **File:** `backend/igny8_core/ai/ai_core.py`
|
|
||||||
- **Class:** `AICore`
|
|
||||||
- **Purpose:** Centralized AI request handler for all text generation
|
|
||||||
- **Methods:**
|
|
||||||
- `run_ai_request` - Makes API call to OpenAI/Runware
|
|
||||||
- `extract_json` - Extracts JSON from response (handles markdown code blocks)
|
|
||||||
|
|
||||||
#### Prompt Registry
|
|
||||||
- **File:** `backend/igny8_core/ai/prompts.py`
|
|
||||||
- **Class:** `PromptRegistry`
|
|
||||||
- **Purpose:** Centralized prompt management with hierarchical resolution
|
|
||||||
- **Method:** `get_prompt` - Gets prompt with resolution order:
|
|
||||||
1. Task-level prompt_override (if exists)
|
|
||||||
2. DB prompt for (account, function)
|
|
||||||
3. Default fallback from DEFAULT_PROMPTS registry
|
|
||||||
- **Prompt Types:**
|
|
||||||
- `clustering` - For auto_cluster function
|
|
||||||
- `ideas` - For generate_ideas function
|
|
||||||
- `content_generation` - For generate_content function
|
|
||||||
- **Context Placeholders:**
|
|
||||||
- `[IGNY8_KEYWORDS]` - Replaced with keyword list
|
|
||||||
- `[IGNY8_CLUSTERS]` - Replaced with cluster list
|
|
||||||
- `[IGNY8_CLUSTER_KEYWORDS]` - Replaced with cluster keywords
|
|
||||||
- `[IGNY8_IDEA]` - Replaced with idea data
|
|
||||||
- `[IGNY8_CLUSTER]` - Replaced with cluster data
|
|
||||||
- `[IGNY8_KEYWORDS]` - Replaced with keywords (for content)
|
|
||||||
|
|
||||||
#### Model Settings
|
|
||||||
- **File:** `backend/igny8_core/ai/settings.py`
|
|
||||||
- **Constants:**
|
|
||||||
- `MODEL_CONFIG` - Model configurations per function (model, max_tokens, temperature, response_format)
|
|
||||||
- `FUNCTION_ALIASES` - Legacy function name mappings
|
|
||||||
- **Functions:**
|
|
||||||
- `get_model_config` - Gets model config for function (reads from IntegrationSettings if account provided)
|
|
||||||
- `get_model` - Gets model name for function
|
|
||||||
- `get_max_tokens` - Gets max tokens for function
|
|
||||||
- `get_temperature` - Gets temperature for function
|
|
||||||
|
|
||||||
#### Validators
|
|
||||||
- **File:** `backend/igny8_core/ai/validators.py`
|
|
||||||
- **Functions:**
|
|
||||||
- `validate_ids` - Validates 'ids' array in payload
|
|
||||||
- `validate_keywords_exist` - Validates keywords exist in database
|
|
||||||
- `validate_cluster_exists` - Validates cluster exists
|
|
||||||
- `validate_tasks_exist` - Validates tasks exist
|
|
||||||
- `validate_cluster_limits` - Validates plan limits (currently disabled - always returns valid)
|
|
||||||
- `validate_api_key` - Validates API key is configured
|
|
||||||
- `validate_model` - Validates model is in supported list
|
|
||||||
- `validate_image_size` - Validates image size for model
|
|
||||||
|
|
||||||
#### Progress Tracking
|
|
||||||
- **File:** `backend/igny8_core/ai/tracker.py`
|
|
||||||
- **Classes:**
|
|
||||||
- `StepTracker` - Tracks request/response steps
|
|
||||||
- `ProgressTracker` - Tracks Celery progress updates
|
|
||||||
- `CostTracker` - Tracks API costs and tokens
|
|
||||||
- `ConsoleStepTracker` - Console-based step logging
|
|
||||||
|
|
||||||
#### Database Logging
|
|
||||||
- **File:** `backend/igny8_core/ai/models.py`
|
|
||||||
- **Model:** `AITaskLog`
|
|
||||||
- **Fields:** `task_id`, `function_name`, `account`, `phase`, `message`, `status`, `duration`, `cost`, `tokens`, `request_steps`, `response_steps`, `error`, `payload`, `result`
|
|
||||||
|
|
||||||
### 1.2 Execution Flow (All Functions)
|
|
||||||
|
|
||||||
```
|
|
||||||
1. API Endpoint (views.py)
|
|
||||||
↓
|
|
||||||
2. run_ai_task (tasks.py)
|
|
||||||
- Gets account from account_id
|
|
||||||
- Gets function instance from registry
|
|
||||||
- Creates AIEngine
|
|
||||||
↓
|
|
||||||
3. AIEngine.execute (engine.py)
|
|
||||||
Phase 1: INIT (0-10%)
|
|
||||||
- Calls function.validate()
|
|
||||||
- Updates progress tracker
|
|
||||||
↓
|
|
||||||
Phase 2: PREP (10-25%)
|
|
||||||
- Calls function.prepare()
|
|
||||||
- Calls function.build_prompt()
|
|
||||||
- Updates progress tracker
|
|
||||||
↓
|
|
||||||
Phase 3: AI_CALL (25-70%)
|
|
||||||
- Gets model config from settings
|
|
||||||
- Calls AICore.run_ai_request()
|
|
||||||
- Tracks cost and tokens
|
|
||||||
- Updates progress tracker
|
|
||||||
↓
|
|
||||||
Phase 4: PARSE (70-85%)
|
|
||||||
- Calls function.parse_response()
|
|
||||||
- Updates progress tracker
|
|
||||||
↓
|
|
||||||
Phase 5: SAVE (85-98%)
|
|
||||||
- Calls function.save_output()
|
|
||||||
- Logs credit usage
|
|
||||||
- Updates progress tracker
|
|
||||||
↓
|
|
||||||
Phase 6: DONE (98-100%)
|
|
||||||
- Logs to AITaskLog
|
|
||||||
- Returns result
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Auto Cluster Keywords
|
|
||||||
|
|
||||||
### 2.1 Function Implementation
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/functions/auto_cluster.py`
|
|
||||||
- **Class:** `AutoClusterFunction`
|
|
||||||
- **Inherits:** `BaseAIFunction`
|
|
||||||
|
|
||||||
### 2.2 API Endpoint
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/views.py`
|
|
||||||
- **ViewSet:** `KeywordViewSet`
|
|
||||||
- **Action:** `auto_cluster`
|
|
||||||
- **Method:** POST
|
|
||||||
- **URL Path:** `/v1/planner/keywords/auto_cluster/`
|
|
||||||
- **Payload:**
|
|
||||||
- `ids` (list[int]) - Keyword IDs to cluster
|
|
||||||
- `sector_id` (int, optional) - Sector ID for filtering
|
|
||||||
- **Response:**
|
|
||||||
- `success` (bool)
|
|
||||||
- `task_id` (str) - Celery task ID if async
|
|
||||||
- `clusters_created` (int) - Number of clusters created
|
|
||||||
- `keywords_updated` (int) - Number of keywords updated
|
|
||||||
- `message` (str)
|
|
||||||
|
|
||||||
### 2.3 Function Methods
|
|
||||||
|
|
||||||
#### `get_name()`
|
|
||||||
- **Returns:** `'auto_cluster'`
|
|
||||||
|
|
||||||
#### `get_metadata()`
|
|
||||||
- **Returns:** Dict with `display_name`, `description`, `phases` (INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
|
||||||
|
|
||||||
#### `get_max_items()`
|
|
||||||
- **Returns:** `None` (no limit)
|
|
||||||
|
|
||||||
#### `validate(payload, account)`
|
|
||||||
- **Validates:**
|
|
||||||
- Calls `validate_ids` to check for 'ids' array
|
|
||||||
- Calls `validate_keywords_exist` to verify keywords exist
|
|
||||||
- **Returns:** Dict with `valid` (bool) and optional `error` (str)
|
|
||||||
|
|
||||||
#### `prepare(payload, account)`
|
|
||||||
- **Loads:**
|
|
||||||
- Keywords from database (filters by `ids`, `account`, optional `sector_id`)
|
|
||||||
- Uses `select_related` for: `account`, `site`, `site__account`, `sector`, `sector__site`
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- `keywords` (list[Keyword objects])
|
|
||||||
- `keyword_data` (list[dict]) - Formatted data with: `id`, `keyword`, `volume`, `difficulty`, `intent`
|
|
||||||
- `sector_id` (int, optional)
|
|
||||||
|
|
||||||
#### `build_prompt(data, account)`
|
|
||||||
- **Gets Prompt:**
|
|
||||||
- Calls `PromptRegistry.get_prompt(function_name='auto_cluster', account, context)`
|
|
||||||
- Context includes: `KEYWORDS` (formatted keyword list), optional `SECTOR` (sector name)
|
|
||||||
- **Formatting:**
|
|
||||||
- Formats keywords as: `"- {keyword} (Volume: {volume}, Difficulty: {difficulty}, Intent: {intent})"`
|
|
||||||
- Replaces `[IGNY8_KEYWORDS]` placeholder
|
|
||||||
- Adds JSON mode instruction if not present
|
|
||||||
- **Returns:** Prompt string
|
|
||||||
|
|
||||||
#### `parse_response(response, step_tracker)`
|
|
||||||
- **Parsing:**
|
|
||||||
- Tries direct JSON parse first
|
|
||||||
- Falls back to `AICore.extract_json()` if needed (handles markdown code blocks)
|
|
||||||
- **Extraction:**
|
|
||||||
- Extracts `clusters` array from JSON
|
|
||||||
- Handles both dict with 'clusters' key and direct array
|
|
||||||
- **Returns:** List[Dict] with cluster data:
|
|
||||||
- `name` (str) - Cluster name
|
|
||||||
- `description` (str) - Cluster description
|
|
||||||
- `keywords` (list[str]) - List of keyword strings
|
|
||||||
|
|
||||||
#### `save_output(parsed, original_data, account, progress_tracker, step_tracker)`
|
|
||||||
- **Input:**
|
|
||||||
- `parsed` - List of cluster dicts from parse_response
|
|
||||||
- `original_data` - Dict from prepare() with `keywords` and `sector_id`
|
|
||||||
- **Process:**
|
|
||||||
- Gets account, site, sector from first keyword
|
|
||||||
- For each cluster in parsed:
|
|
||||||
- Gets or creates `Clusters` record:
|
|
||||||
- Fields: `name`, `description`, `account`, `site`, `sector`, `status='active'`
|
|
||||||
- Uses `get_or_create` with name + account + site + sector
|
|
||||||
- Matches keywords (case-insensitive):
|
|
||||||
- Normalizes cluster keywords and available keywords to lowercase
|
|
||||||
- Updates matched `Keywords` records:
|
|
||||||
- Sets `cluster` foreign key
|
|
||||||
- Sets `status='mapped'`
|
|
||||||
- Recalculates cluster metrics:
|
|
||||||
- `keywords_count` - Count of keywords in cluster
|
|
||||||
- `volume` - Sum of keyword volumes (uses `volume_override` if available, else `seed_keyword__volume`)
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- `count` (int) - Clusters created
|
|
||||||
- `clusters_created` (int) - Clusters created
|
|
||||||
- `keywords_updated` (int) - Keywords updated
|
|
||||||
|
|
||||||
### 2.4 Database Models
|
|
||||||
|
|
||||||
#### Keywords Model
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/models.py`
|
|
||||||
- **Model:** `Keywords`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `id` - Keyword ID
|
|
||||||
- `seed_keyword` (ForeignKey) - Reference to SeedKeyword
|
|
||||||
- `keyword` (property) - Gets keyword text from seed_keyword
|
|
||||||
- `volume` (property) - Gets volume from volume_override or seed_keyword
|
|
||||||
- `difficulty` (property) - Gets difficulty from difficulty_override or seed_keyword
|
|
||||||
- `intent` (property) - Gets intent from seed_keyword
|
|
||||||
- `cluster` (ForeignKey) - Assigned cluster
|
|
||||||
- `status` - Status ('active', 'pending', 'mapped', 'archived')
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel
|
|
||||||
|
|
||||||
#### Clusters Model
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/models.py`
|
|
||||||
- **Model:** `Clusters`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `name` - Cluster name (unique)
|
|
||||||
- `description` - Cluster description
|
|
||||||
- `keywords_count` - Count of keywords (recalculated)
|
|
||||||
- `volume` - Sum of keyword volumes (recalculated)
|
|
||||||
- `status` - Status ('active')
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel
|
|
||||||
|
|
||||||
### 2.5 AI Response Format
|
|
||||||
|
|
||||||
**Expected JSON:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"clusters": [
|
|
||||||
{
|
|
||||||
"name": "Cluster Name",
|
|
||||||
"description": "Cluster description",
|
|
||||||
"keywords": ["keyword1", "keyword2", "keyword3"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.6 Progress Messages
|
|
||||||
|
|
||||||
- **INIT:** "Validating {keyword1}, {keyword2}, {keyword3} and {X} more keywords" (shows first 3, then count)
|
|
||||||
- **PREP:** "Loading {count} keyword(s)"
|
|
||||||
- **AI_CALL:** "Generating clusters with Igny8 Semantic SEO Model"
|
|
||||||
- **PARSE:** "{count} cluster(s) created"
|
|
||||||
- **SAVE:** "Saving {count} cluster(s)"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Generate Ideas
|
|
||||||
|
|
||||||
### 3.1 Function Implementation
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/functions/generate_ideas.py`
|
|
||||||
- **Class:** `GenerateIdeasFunction`
|
|
||||||
- **Inherits:** `BaseAIFunction`
|
|
||||||
|
|
||||||
### 3.2 API Endpoint
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/views.py`
|
|
||||||
- **ViewSet:** `ClusterViewSet`
|
|
||||||
- **Action:** `auto_generate_ideas`
|
|
||||||
- **Method:** POST
|
|
||||||
- **URL Path:** `/v1/planner/clusters/auto_generate_ideas/`
|
|
||||||
- **Payload:**
|
|
||||||
- `ids` (list[int]) - Cluster IDs (max 10)
|
|
||||||
- **Response:**
|
|
||||||
- `success` (bool)
|
|
||||||
- `task_id` (str) - Celery task ID if async
|
|
||||||
- `ideas_created` (int) - Number of ideas created
|
|
||||||
- `message` (str)
|
|
||||||
|
|
||||||
### 3.3 Function Methods
|
|
||||||
|
|
||||||
#### `get_name()`
|
|
||||||
- **Returns:** `'generate_ideas'`
|
|
||||||
|
|
||||||
#### `get_metadata()`
|
|
||||||
- **Returns:** Dict with `display_name`, `description`, `phases` (INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
|
||||||
|
|
||||||
#### `get_max_items()`
|
|
||||||
- **Returns:** `10` (max clusters per generation)
|
|
||||||
|
|
||||||
#### `validate(payload, account)`
|
|
||||||
- **Validates:**
|
|
||||||
- Calls `super().validate()` to check for 'ids' array and max_items limit
|
|
||||||
- Calls `validate_cluster_exists` for first cluster ID
|
|
||||||
- Calls `validate_cluster_limits` for plan limits (currently disabled)
|
|
||||||
- **Returns:** Dict with `valid` (bool) and optional `error` (str)
|
|
||||||
|
|
||||||
#### `prepare(payload, account)`
|
|
||||||
- **Loads:**
|
|
||||||
- Clusters from database (filters by `ids`, `account`)
|
|
||||||
- Uses `select_related` for: `sector`, `account`, `site`, `sector__site`
|
|
||||||
- Uses `prefetch_related` for: `keywords`
|
|
||||||
- **Gets Keywords:**
|
|
||||||
- For each cluster, loads `Keywords` with `select_related('seed_keyword')`
|
|
||||||
- Extracts keyword text from `seed_keyword.keyword`
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- `clusters` (list[Cluster objects])
|
|
||||||
- `cluster_data` (list[dict]) - Formatted data with: `id`, `name`, `description`, `keywords` (list[str])
|
|
||||||
- `account` (Account object)
|
|
||||||
|
|
||||||
#### `build_prompt(data, account)`
|
|
||||||
- **Gets Prompt:**
|
|
||||||
- Calls `PromptRegistry.get_prompt(function_name='generate_ideas', account, context)`
|
|
||||||
- Context includes:
|
|
||||||
- `CLUSTERS` - Formatted cluster list: `"Cluster ID: {id} | Name: {name} | Description: {description}"`
|
|
||||||
- `CLUSTER_KEYWORDS` - Formatted cluster keywords: `"Cluster ID: {id} | Name: {name} | Keywords: {keyword1}, {keyword2}"`
|
|
||||||
- **Replaces Placeholders:**
|
|
||||||
- `[IGNY8_CLUSTERS]` → clusters_text
|
|
||||||
- `[IGNY8_CLUSTER_KEYWORDS]` → cluster_keywords_text
|
|
||||||
- **Returns:** Prompt string
|
|
||||||
|
|
||||||
#### `parse_response(response, step_tracker)`
|
|
||||||
- **Parsing:**
|
|
||||||
- Calls `AICore.extract_json()` to extract JSON from response
|
|
||||||
- Validates 'ideas' key exists in JSON
|
|
||||||
- **Returns:** List[Dict] with idea data:
|
|
||||||
- `title` (str) - Idea title
|
|
||||||
- `description` (str or dict) - Idea description (can be JSON string)
|
|
||||||
- `content_type` (str) - Content type ('blog_post', 'article', etc.)
|
|
||||||
- `content_structure` (str) - Content structure ('cluster_hub', 'supporting_page', etc.)
|
|
||||||
- `cluster_id` (int, optional) - Cluster ID reference
|
|
||||||
- `cluster_name` (str, optional) - Cluster name reference
|
|
||||||
- `estimated_word_count` (int) - Estimated word count
|
|
||||||
- `covered_keywords` or `target_keywords` (str) - Target keywords
|
|
||||||
|
|
||||||
#### `save_output(parsed, original_data, account, progress_tracker, step_tracker)`
|
|
||||||
- **Input:**
|
|
||||||
- `parsed` - List of idea dicts from parse_response
|
|
||||||
- `original_data` - Dict from prepare() with `clusters` and `cluster_data`
|
|
||||||
- **Process:**
|
|
||||||
- For each idea in parsed:
|
|
||||||
- Matches cluster:
|
|
||||||
- First tries by `cluster_id` from AI response
|
|
||||||
- Falls back to `cluster_name` matching
|
|
||||||
- Last resort: position-based matching (first idea → first cluster)
|
|
||||||
- Gets site from cluster (or cluster.sector.site)
|
|
||||||
- Handles description:
|
|
||||||
- If dict, converts to JSON string
|
|
||||||
- If not string, converts to string
|
|
||||||
- Creates `ContentIdeas` record:
|
|
||||||
- Fields:
|
|
||||||
- `idea_title` - From `title`
|
|
||||||
- `description` - Processed description
|
|
||||||
- `content_type` - From `content_type` (default: 'blog_post')
|
|
||||||
- `content_structure` - From `content_structure` (default: 'supporting_page')
|
|
||||||
- `target_keywords` - From `covered_keywords` or `target_keywords`
|
|
||||||
- `keyword_cluster` - Matched cluster
|
|
||||||
- `estimated_word_count` - From `estimated_word_count` (default: 1500)
|
|
||||||
- `status` - 'new'
|
|
||||||
- `account`, `site`, `sector` - From cluster
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- `count` (int) - Ideas created
|
|
||||||
- `ideas_created` (int) - Ideas created
|
|
||||||
|
|
||||||
### 3.4 Database Models
|
|
||||||
|
|
||||||
#### Clusters Model
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/models.py`
|
|
||||||
- **Model:** `Clusters`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `id` - Cluster ID
|
|
||||||
- `name` - Cluster name
|
|
||||||
- `description` - Cluster description
|
|
||||||
- `keywords` (related_name) - Related Keywords
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel
|
|
||||||
|
|
||||||
#### ContentIdeas Model
|
|
||||||
- **File:** `backend/igny8_core/modules/planner/models.py`
|
|
||||||
- **Model:** `ContentIdeas`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `idea_title` - Idea title
|
|
||||||
- `description` - Idea description (can be JSON string)
|
|
||||||
- `content_type` - Content type ('blog_post', 'article', 'guide', 'tutorial')
|
|
||||||
- `content_structure` - Content structure ('cluster_hub', 'landing_page', 'pillar_page', 'supporting_page')
|
|
||||||
- `target_keywords` - Target keywords string
|
|
||||||
- `keyword_cluster` (ForeignKey) - Related cluster
|
|
||||||
- `estimated_word_count` - Estimated word count
|
|
||||||
- `status` - Status ('new', 'scheduled', 'published')
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel
|
|
||||||
|
|
||||||
### 3.5 AI Response Format
|
|
||||||
|
|
||||||
**Expected JSON:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"ideas": [
|
|
||||||
{
|
|
||||||
"title": "Idea Title",
|
|
||||||
"description": "Idea description or JSON structure",
|
|
||||||
"content_type": "blog_post",
|
|
||||||
"content_structure": "supporting_page",
|
|
||||||
"cluster_id": 1,
|
|
||||||
"cluster_name": "Cluster Name",
|
|
||||||
"estimated_word_count": 1500,
|
|
||||||
"covered_keywords": "keyword1, keyword2"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.6 Progress Messages
|
|
||||||
|
|
||||||
- **INIT:** "Verifying cluster integrity"
|
|
||||||
- **PREP:** "Loading cluster keywords"
|
|
||||||
- **AI_CALL:** "Generating ideas with Igny8 Semantic AI"
|
|
||||||
- **PARSE:** "{count} high-opportunity idea(s) generated"
|
|
||||||
- **SAVE:** "Content Outline for Ideas generated"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Generate Content
|
|
||||||
|
|
||||||
### 4.1 Function Implementation
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/functions/generate_content.py`
|
|
||||||
- **Class:** `GenerateContentFunction`
|
|
||||||
- **Inherits:** `BaseAIFunction`
|
|
||||||
|
|
||||||
### 4.2 API Endpoint
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/modules/writer/views.py`
|
|
||||||
- **ViewSet:** `TasksViewSet`
|
|
||||||
- **Action:** `auto_generate_content`
|
|
||||||
- **Method:** POST
|
|
||||||
- **URL Path:** `/v1/writer/tasks/auto_generate_content/`
|
|
||||||
- **Payload:**
|
|
||||||
- `ids` (list[int]) - Task IDs (max 10)
|
|
||||||
- **Response:**
|
|
||||||
- `success` (bool)
|
|
||||||
- `task_id` (str) - Celery task ID if async
|
|
||||||
- `tasks_updated` (int) - Number of tasks updated
|
|
||||||
- `message` (str)
|
|
||||||
|
|
||||||
### 4.3 Function Methods
|
|
||||||
|
|
||||||
#### `get_name()`
|
|
||||||
- **Returns:** `'generate_content'`
|
|
||||||
|
|
||||||
#### `get_metadata()`
|
|
||||||
- **Returns:** Dict with `display_name`, `description`, `phases` (INIT, PREP, AI_CALL, PARSE, SAVE, DONE)
|
|
||||||
|
|
||||||
#### `get_max_items()`
|
|
||||||
- **Returns:** `50` (max tasks per batch)
|
|
||||||
|
|
||||||
#### `validate(payload, account)`
|
|
||||||
- **Validates:**
|
|
||||||
- Calls `super().validate()` to check for 'ids' array and max_items limit
|
|
||||||
- Calls `validate_tasks_exist` to verify tasks exist
|
|
||||||
- **Returns:** Dict with `valid` (bool) and optional `error` (str)
|
|
||||||
|
|
||||||
#### `prepare(payload, account)`
|
|
||||||
- **Loads:**
|
|
||||||
- Tasks from database (filters by `ids`, `account`)
|
|
||||||
- Uses `select_related` for: `account`, `site`, `sector`, `cluster`, `idea`
|
|
||||||
- **Returns:** List[Task objects]
|
|
||||||
|
|
||||||
#### `build_prompt(data, account)`
|
|
||||||
- **Input:** Can be single Task or list[Task] (handles first task if list)
|
|
||||||
- **Builds Idea Data:**
|
|
||||||
- `title` - From task.title
|
|
||||||
- `description` - From task.description
|
|
||||||
- `outline` - From task.idea.description (handles JSON structure):
|
|
||||||
- If JSON, formats as: `"## {H2 heading}\n### {H3 subheading}\nContent Type: {type}\nDetails: {details}"`
|
|
||||||
- If plain text, uses as-is
|
|
||||||
- `structure` - From task.idea.content_structure or task.content_structure
|
|
||||||
- `type` - From task.idea.content_type or task.content_type
|
|
||||||
- `estimated_word_count` - From task.idea.estimated_word_count
|
|
||||||
- **Builds Cluster Data:**
|
|
||||||
- `cluster_name` - From task.cluster.name
|
|
||||||
- `description` - From task.cluster.description
|
|
||||||
- `status` - From task.cluster.status
|
|
||||||
- **Builds Keywords Data:**
|
|
||||||
- From task.keywords (legacy) or task.idea.target_keywords
|
|
||||||
- **Gets Prompt:**
|
|
||||||
- Calls `PromptRegistry.get_prompt(function_name='generate_content', account, task, context)`
|
|
||||||
- Context includes:
|
|
||||||
- `IDEA` - Formatted idea data string
|
|
||||||
- `CLUSTER` - Formatted cluster data string
|
|
||||||
- `KEYWORDS` - Keywords string
|
|
||||||
- **Returns:** Prompt string
|
|
||||||
|
|
||||||
#### `parse_response(response, step_tracker)`
|
|
||||||
- **Parsing:**
|
|
||||||
- First tries JSON parse:
|
|
||||||
- If successful and dict, returns dict
|
|
||||||
- Falls back to plain text:
|
|
||||||
- Calls `normalize_content()` from `content_normalizer` to convert to HTML
|
|
||||||
- Returns dict with `content` field
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- **If JSON:**
|
|
||||||
- `content` (str) - HTML content
|
|
||||||
- `title` (str, optional) - Content title
|
|
||||||
- `meta_title` (str, optional) - Meta title
|
|
||||||
- `meta_description` (str, optional) - Meta description
|
|
||||||
- `word_count` (int, optional) - Word count
|
|
||||||
- `primary_keyword` (str, optional) - Primary keyword
|
|
||||||
- `secondary_keywords` (list, optional) - Secondary keywords
|
|
||||||
- `tags` (list, optional) - Tags
|
|
||||||
- `categories` (list, optional) - Categories
|
|
||||||
- **If Plain Text:**
|
|
||||||
- `content` (str) - Normalized HTML content
|
|
||||||
|
|
||||||
#### `save_output(parsed, original_data, account, progress_tracker, step_tracker)`
|
|
||||||
- **Input:**
|
|
||||||
- `parsed` - Dict from parse_response
|
|
||||||
- `original_data` - Task object or list[Task] (handles first task if list)
|
|
||||||
- **Process:**
|
|
||||||
- Extracts content fields from parsed dict:
|
|
||||||
- `content_html` - From `content` field
|
|
||||||
- `title` - From `title` or task.title
|
|
||||||
- `meta_title` - From `meta_title` or task.meta_title or task.title
|
|
||||||
- `meta_description` - From `meta_description` or task.meta_description or task.description
|
|
||||||
- `word_count` - From `word_count` or calculated from content
|
|
||||||
- `primary_keyword` - From `primary_keyword`
|
|
||||||
- `secondary_keywords` - From `secondary_keywords` (converts to list if needed)
|
|
||||||
- `tags` - From `tags` (converts to list if needed)
|
|
||||||
- `categories` - From `categories` (converts to list if needed)
|
|
||||||
- Calculates word count if not provided:
|
|
||||||
- Strips HTML tags and counts words
|
|
||||||
- Gets or creates `Content` record:
|
|
||||||
- Uses `get_or_create` with `task` (OneToOne relationship)
|
|
||||||
- Defaults: `html_content`, `word_count`, `status='draft'`, `account`, `site`, `sector`
|
|
||||||
- Updates `Content` fields:
|
|
||||||
- `html_content` - Content HTML
|
|
||||||
- `word_count` - Word count
|
|
||||||
- `title` - Content title
|
|
||||||
- `meta_title` - Meta title
|
|
||||||
- `meta_description` - Meta description
|
|
||||||
- `primary_keyword` - Primary keyword
|
|
||||||
- `secondary_keywords` - Secondary keywords (JSONField)
|
|
||||||
- `tags` - Tags (JSONField)
|
|
||||||
- `categories` - Categories (JSONField)
|
|
||||||
- `status` - Always 'draft' for newly generated content
|
|
||||||
- `metadata` - Extra fields from parsed dict (excludes standard fields)
|
|
||||||
- `account`, `site`, `sector`, `task` - Aligned from task
|
|
||||||
- Updates `Tasks` record:
|
|
||||||
- Sets `status='completed'`
|
|
||||||
- Updates `updated_at`
|
|
||||||
- **Returns:** Dict with:
|
|
||||||
- `count` (int) - Tasks updated (always 1 per task)
|
|
||||||
- `tasks_updated` (int) - Tasks updated
|
|
||||||
- `word_count` (int) - Word count
|
|
||||||
|
|
||||||
### 4.4 Database Models
|
|
||||||
|
|
||||||
#### Tasks Model
|
|
||||||
- **File:** `backend/igny8_core/modules/writer/models.py`
|
|
||||||
- **Model:** `Tasks`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `id` - Task ID
|
|
||||||
- `title` - Task title
|
|
||||||
- `description` - Task description
|
|
||||||
- `keywords` - Keywords string (legacy)
|
|
||||||
- `cluster` (ForeignKey) - Related cluster
|
|
||||||
- `idea` (ForeignKey) - Related ContentIdeas
|
|
||||||
- `content_structure` - Content structure
|
|
||||||
- `content_type` - Content type
|
|
||||||
- `status` - Status ('queued', 'completed')
|
|
||||||
- `meta_title` - Meta title
|
|
||||||
- `meta_description` - Meta description
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel
|
|
||||||
|
|
||||||
#### Content Model
|
|
||||||
- **File:** `backend/igny8_core/modules/writer/models.py`
|
|
||||||
- **Model:** `Content`
|
|
||||||
- **Fields Used:**
|
|
||||||
- `task` (OneToOneField) - Related task
|
|
||||||
- `html_content` - HTML content
|
|
||||||
- `word_count` - Word count
|
|
||||||
- `title` - Content title
|
|
||||||
- `meta_title` - Meta title
|
|
||||||
- `meta_description` - Meta description
|
|
||||||
- `primary_keyword` - Primary keyword
|
|
||||||
- `secondary_keywords` (JSONField) - Secondary keywords list
|
|
||||||
- `tags` (JSONField) - Tags list
|
|
||||||
- `categories` (JSONField) - Categories list
|
|
||||||
- `status` - Status ('draft', 'review', 'published')
|
|
||||||
- `metadata` (JSONField) - Additional metadata
|
|
||||||
- `account`, `site`, `sector` - From SiteSectorBaseModel (auto-set from task)
|
|
||||||
|
|
||||||
### 4.5 AI Response Format
|
|
||||||
|
|
||||||
**Expected JSON:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"content": "<html>Content HTML</html>",
|
|
||||||
"title": "Content Title",
|
|
||||||
"meta_title": "Meta Title",
|
|
||||||
"meta_description": "Meta description",
|
|
||||||
"word_count": 1500,
|
|
||||||
"primary_keyword": "primary keyword",
|
|
||||||
"secondary_keywords": ["keyword1", "keyword2"],
|
|
||||||
"tags": ["tag1", "tag2"],
|
|
||||||
"categories": ["category1"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Or Plain Text:**
|
|
||||||
```
|
|
||||||
Plain text content that will be normalized to HTML
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.6 Progress Messages
|
|
||||||
|
|
||||||
- **INIT:** "Validating task"
|
|
||||||
- **PREP:** "Preparing content idea"
|
|
||||||
- **AI_CALL:** "Writing article with Igny8 Semantic AI"
|
|
||||||
- **PARSE:** "{count} article(s) created"
|
|
||||||
- **SAVE:** "Saving article"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Change Guide
|
|
||||||
|
|
||||||
### 5.1 Where to Change Validation Logic
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/validators.py`
|
|
||||||
- **Functions:** `validate_ids`, `validate_keywords_exist`, `validate_cluster_exists`, `validate_tasks_exist`
|
|
||||||
- **Or:** Override `validate()` method in function class
|
|
||||||
|
|
||||||
### 5.2 Where to Change Data Loading
|
|
||||||
|
|
||||||
- **File:** Function-specific file (e.g., `auto_cluster.py`)
|
|
||||||
- **Method:** `prepare()`
|
|
||||||
- **Change:** Modify queryset filters, select_related, prefetch_related
|
|
||||||
|
|
||||||
### 5.3 Where to Change Prompts
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/prompts.py`
|
|
||||||
- **Method:** `PromptRegistry.get_prompt()`
|
|
||||||
- **Change:** Modify `DEFAULT_PROMPTS` dict or update database prompts
|
|
||||||
|
|
||||||
### 5.4 Where to Change Model Configuration
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/settings.py`
|
|
||||||
- **Constant:** `MODEL_CONFIG`
|
|
||||||
- **Change:** Update model, max_tokens, temperature, response_format per function
|
|
||||||
|
|
||||||
### 5.5 Where to Change Response Parsing
|
|
||||||
|
|
||||||
- **File:** Function-specific file (e.g., `generate_content.py`)
|
|
||||||
- **Method:** `parse_response()`
|
|
||||||
- **Change:** Modify JSON extraction or plain text handling
|
|
||||||
|
|
||||||
### 5.6 Where to Change Database Saving
|
|
||||||
|
|
||||||
- **File:** Function-specific file (e.g., `auto_cluster.py`)
|
|
||||||
- **Method:** `save_output()`
|
|
||||||
- **Change:** Modify model creation/update logic, field mappings
|
|
||||||
|
|
||||||
### 5.7 Where to Change Progress Messages
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/engine.py`
|
|
||||||
- **Methods:** `_get_prep_message()`, `_get_ai_call_message()`, `_get_parse_message()`, `_get_save_message()`
|
|
||||||
- **Or:** Override in function class `get_metadata()` phases
|
|
||||||
|
|
||||||
### 5.8 Where to Change Error Handling
|
|
||||||
|
|
||||||
- **File:** `backend/igny8_core/ai/engine.py`
|
|
||||||
- **Method:** `_handle_error()`
|
|
||||||
- **Change:** Modify error logging, error response format
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Dependencies
|
|
||||||
|
|
||||||
### 6.1 Function Dependencies
|
|
||||||
|
|
||||||
- All functions depend on: `BaseAIFunction`, `AICore`, `PromptRegistry`, `get_model_config`
|
|
||||||
- Clustering depends on: `Keywords`, `Clusters` models
|
|
||||||
- Ideas depends on: `Clusters`, `ContentIdeas`, `Keywords` models
|
|
||||||
- Content depends on: `Tasks`, `Content`, `ContentIdeas`, `Clusters` models
|
|
||||||
|
|
||||||
### 6.2 External Dependencies
|
|
||||||
|
|
||||||
- **Celery:** For async task execution (`run_ai_task`)
|
|
||||||
- **OpenAI API:** For AI text generation (via `AICore.run_ai_request`)
|
|
||||||
- **Django ORM:** For database operations
|
|
||||||
- **IntegrationSettings:** For account-specific model configuration
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Key Relationships
|
|
||||||
|
|
||||||
### 7.1 Clustering Flow
|
|
||||||
```
|
|
||||||
Keywords → Clusters (many-to-one)
|
|
||||||
- Keywords.cluster (ForeignKey)
|
|
||||||
- Clusters.keywords (related_name)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.2 Ideas Flow
|
|
||||||
```
|
|
||||||
Clusters → ContentIdeas (one-to-many)
|
|
||||||
- ContentIdeas.keyword_cluster (ForeignKey)
|
|
||||||
- Clusters.ideas (related_name, if exists)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.3 Content Flow
|
|
||||||
```
|
|
||||||
Tasks → Content (one-to-one)
|
|
||||||
- Content.task (OneToOneField)
|
|
||||||
- Tasks.content_record (related_name)
|
|
||||||
|
|
||||||
Tasks → ContentIdeas (many-to-one)
|
|
||||||
- Tasks.idea (ForeignKey)
|
|
||||||
- ContentIdeas.tasks (related_name)
|
|
||||||
|
|
||||||
Tasks → Clusters (many-to-one)
|
|
||||||
- Tasks.cluster (ForeignKey)
|
|
||||||
- Clusters.tasks (related_name)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Notes
|
|
||||||
|
|
||||||
- All functions use the same execution pipeline through `AIEngine.execute()`
|
|
||||||
- Progress tracking is handled automatically by `AIEngine`
|
|
||||||
- Cost tracking is handled automatically by `CostTracker`
|
|
||||||
- Database logging is handled automatically by `AITaskLog`
|
|
||||||
- Model configuration can be overridden per account via `IntegrationSettings`
|
|
||||||
- Prompts can be overridden per account via database prompts
|
|
||||||
- All functions support both async (Celery) and sync execution
|
|
||||||
- Error handling is centralized in `AIEngine._handle_error()`
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user