# AI Functions Reference

**Last Verified:** January 6, 2026

---

## Overview

IGNY8's AI engine provides functions for content planning and generation. Located in `backend/igny8_core/ai/`.

**Providers (v1.4.0):**
- **OpenAI** - GPT-4 for text, DALL-E 3 for images (via `IntegrationProvider`)
- **Anthropic** - Claude models for text (via `IntegrationProvider`)
- **Runware** - Alternative image generation (via `IntegrationProvider`)

**New in v1.4.0:**
- Provider API keys stored in `IntegrationProvider` model
- Model configurations stored in `AIModelConfig` model
- System defaults stored in `SystemAISettings` singleton
- Credit-based pricing per model via `AIModelConfig.tokens_per_credit` / `credits_per_image`

---

## Architecture (Updated v1.4.0)

```
┌─────────────────────────────────────────────────────────────────┐
│                        AI ENGINE                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐      │
│  │   AIEngine   │───►│   Function   │───►│   Provider   │      │
│  │   (router)   │    │   (logic)    │    │   (API)      │      │
│  └──────────────┘    └──────────────┘    └──────────────┘      │
│         │                                        ▲              │
│         │                                        │              │
│         ▼                                        │              │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐      │
│  │ModelRegistry │───►│AIModelConfig │───►│Integration   │      │
│  │  (service)   │    │  (database)  │    │  Provider    │      │
│  └──────────────┘    └──────────────┘    └──────────────┘      │
│                                                                  │
│  Functions:                                                      │
│  • AutoClusterKeywords                                          │
│  • GenerateContentIdeas                                         │
│  • GenerateContent                                              │
│  • GenerateImages                                               │
│  • GenerateImagePrompts                                         │
│  • OptimizeContent (pending)                                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

---

## Model Registry (NEW v1.4.0)

**Location:** `backend/igny8_core/ai/model_registry.py`

Central registry for AI model configurations with caching.

```python
from igny8_core.ai.model_registry import ModelRegistry

# Get model configuration
model = ModelRegistry.get_model('gpt-4o-mini')

# Get pricing rate
input_rate = ModelRegistry.get_rate('gpt-4o-mini', 'input')

# Calculate cost
cost = ModelRegistry.calculate_cost('gpt-4o-mini', input_tokens=1000, output_tokens=500)

# Get API key for provider
api_key = ModelRegistry.get_api_key('openai')

# Get default model
default_text = ModelRegistry.get_default_model('text')
default_image = ModelRegistry.get_default_model('image')

# List available models
text_models = ModelRegistry.list_models(model_type='text')
image_models = ModelRegistry.list_models(model_type='image', provider='runware')
```

---

## AIEngine

**Location:** `backend/igny8_core/ai/engine.py`

Main orchestrator for AI operations.

```python
class AIEngine:
    def __init__(self, account: Account):
        self.account = account
        self.settings = self._load_settings()  # Uses SystemAISettings + AccountSettings
        self.text_provider = self._init_text_provider()  # Uses ModelRegistry
        self.image_provider = self._init_image_provider()  # Uses ModelRegistry
    
    def auto_cluster(self, keywords: List[Keyword]) -> List[Cluster]:
        """Cluster keywords by topic"""
        
    def generate_ideas(self, cluster: Cluster) -> List[ContentIdea]:
        """Generate content ideas for cluster"""
        
    def generate_content(self, task: Task) -> Content:
        """Generate full article content"""
        
    def generate_images(self, content: Content, count: int = 1, quality_tier: str = 'quality') -> List[ContentImage]:
        """Generate images for content with quality tier selection (v1.4.0)"""
```

---

## Function: AutoClusterKeywords

**Purpose:** Group semantically related keywords into clusters

**Input:**
```python
{
    "keywords": [
        {"id": "...", "keyword": "python tutorial"},
        {"id": "...", "keyword": "learn python"},
        {"id": "...", "keyword": "python basics"},
        ...
    ],
    "site_context": {
        "name": "Tech Blog",
        "industry": "Technology"
    }
}
```

**Output:**
```python
{
    "clusters": [
        {
            "name": "Python Learning Resources",
            "description": "Tutorials and guides for learning Python",
            "keywords": ["python tutorial", "learn python", "python basics"]
        },
        ...
    ]
}
```

**Prompt Template:** `auto_cluster`

**Model:** Default text model (from `AIModelConfig.is_default`)

**Credit Cost:** Based on `AIModelConfig.tokens_per_credit` for model used

---

## Function: GenerateContentIdeas

**Purpose:** Create content ideas from a keyword cluster

**Input:**
```python
{
    "cluster": {
        "name": "Python Learning Resources",
        "description": "...",
        "keywords": [...]
    },
    "site_context": {
        "name": "Tech Blog",
        "industry": "Technology"
    },
    "count": 5  # Number of ideas to generate
}
```

**Output:**
```python
{
    "ideas": [
        {
            "title": "10 Essential Python Tips for Beginners",
            "description": "A comprehensive guide covering...",
            "primary_keyword": "python tutorial",
            "secondary_keywords": ["learn python", "python basics"]
        },
        ...
    ]
}
```

**Prompt Template:** `generate_ideas`

**Model:** Default text model (from `AIModelConfig.is_default`)

**Credit Cost:** Based on `AIModelConfig.tokens_per_credit` for model used

---

## Function: GenerateContent

**Purpose:** Create full article from task brief

**Input:**
```python
{
    "task": {
        "title": "10 Essential Python Tips for Beginners",
        "brief": "Write a comprehensive guide...",
        "primary_keyword": "python tutorial",
        "secondary_keywords": ["learn python", "python basics"]
    },
    "site_context": {
        "name": "Tech Blog",
        "industry": "Technology",
        "tone": "Professional but approachable"
    },
    "options": {
        "target_word_count": 2000,
        "include_headings": True,
        "include_lists": True,
        "include_code_blocks": True,
        "temperature": 0.7,  # From SystemAISettings or AccountSettings override
        "max_tokens": 8192   # From SystemAISettings or AccountSettings override
    }
}
```

**Output:**
```python
{
    "title": "10 Essential Python Tips for Beginners",
    "body": "<h2>Introduction</h2><p>...</p>...",  # Full HTML
    "excerpt": "Learn the essential Python tips...",
    "meta_title": "10 Python Tips for Beginners | Tech Blog",
    "meta_description": "Master Python with these 10 essential tips...",
    "word_count": 2150
}
```

**Prompt Template:** `generate_content`

**Model:** Default text model (from `AIModelConfig.is_default`)

**Credit Cost:** Based on `AIModelConfig.tokens_per_credit` for model used

---

## Function: GenerateImages (Updated v1.4.0)

**Purpose:** Create images for article content with quality tier selection

**Input:**
```python
{
    "content": {
        "title": "10 Essential Python Tips for Beginners",
        "body": "<html>...</html>",
        "primary_keyword": "python tutorial"
    },
    "options": {
        "count": 3,
        "quality_tier": "quality",  # basic (1 credit), quality (5 credits), premium (15 credits)
        "style": "photorealistic",  # From SystemAISettings or override
        "size": "1024x1024"  # From SystemAISettings or override
    }
}
```

**Quality Tiers (v1.4.0):**

| Tier | Model Example | credits_per_image | Description |
|------|---------------|-------------------|-------------|
| basic | runware:97@1 | 1 | Fast generation, simple images |
| quality | dall-e-3 | 5 | Balanced quality and speed |
| premium | google:4@2 | 15 | Best quality, slower |

**Process:**
1. Get quality tier model from `AIModelConfig.get_image_models_by_tier()`
2. Analyze content to identify image opportunities
3. Generate prompts for each image (via `GenerateImagePrompts`)
4. Call image provider API (using `IntegrationProvider.get_api_key()`)
5. Store images and generate thumbnails

**Output:**
```python
{
    "images": [
        {
            "url": "https://storage.../image1.png",
            "thumbnail_url": "https://storage.../image1_thumb.png",
            "alt_text": "Python code example showing...",
            "caption": "Example of Python list comprehension",
            "prompt": "A clean code editor showing Python syntax...",
            "is_featured": True,
            "model_used": "dall-e-3",
            "quality_tier": "quality",
            "credits_used": 5
        },
        ...
    ]
}
```

**Prompt Template:** `generate_image_prompts`

**Model:** Selected by quality tier from `AIModelConfig`

**Credit Cost:** `AIModelConfig.credits_per_image` for selected model

---

## Function: OptimizeContent (Pending)

**Status:** ⏸️ Not yet implemented

**Purpose:** SEO optimize existing content

**Planned Input:**
```python
{
    "content": {
        "title": "...",
        "body": "...",
        "target_keyword": "..."
    },
    "optimization_type": "seo" | "readability" | "both"
}
```

**Planned Output:**
```python
{
    "optimized_title": "...",
    "optimized_body": "...",
    "changes": [
        {"type": "keyword_density", "description": "..."},
        {"type": "heading_structure", "description": "..."},
        ...
    ],
    "score_before": 65,
    "score_after": 85
}
```

---

## Prompt Templates

### System Prompts

Stored in `PromptTemplate` model or defaults in code.

| Template | Purpose |
|----------|---------|
| `auto_cluster` | Keywords → Clusters |
| `generate_ideas` | Cluster → Ideas |
| `generate_content` | Task → Article |
| `generate_image_prompts` | Content → Image prompts |
| `optimize_content` | Content → Optimized (pending) |

### Template Variables

```python
{
    "site_name": "Tech Blog",
    "site_industry": "Technology",
    "site_tone": "Professional",
    "keyword": "python tutorial",
    "keywords": ["python", "tutorial", "learn"],
    "cluster_name": "Python Learning",
    "task_title": "10 Python Tips",
    "task_brief": "Write a guide...",
    "target_word_count": 2000
}
```

### Custom Prompts

Users can customize prompts via Settings → Prompts:

```python
# API
GET /api/v1/system/prompts/{type}/
PUT /api/v1/system/prompts/{type}/
POST /api/v1/system/prompts/{type}/reset/
```

---

## Provider: OpenAI

**Location:** `backend/igny8_core/ai/providers/openai_provider.py`

### Text Generation

```python
class OpenAITextProvider:
    def complete(self, prompt: str, options: dict) -> str:
        response = openai.ChatCompletion.create(
            model=options.get('model', 'gpt-4'),
            messages=[
                {"role": "system", "content": self.system_prompt},
                {"role": "user", "content": prompt}
            ],
            temperature=options.get('temperature', 0.7),
            max_tokens=options.get('max_tokens', 4000)
        )
        return response.choices[0].message.content
```

### Image Generation

```python
class OpenAIImageProvider:
    def generate(self, prompt: str, options: dict) -> str:
        response = openai.Image.create(
            model="dall-e-3",
            prompt=prompt,
            size=options.get('size', '1024x1024'),
            quality=options.get('quality', 'standard'),
            n=1
        )
        return response.data[0].url
```

---

## Provider: Runware

**Location:** `backend/igny8_core/ai/providers/runware_provider.py`

Alternative image generation via Runware API.

```python
class RunwareImageProvider:
    def generate(self, prompt: str, options: dict) -> str:
        response = self.client.generate(
            prompt=prompt,
            width=options.get('width', 1024),
            height=options.get('height', 1024),
            model=options.get('model', 'default')
        )
        return response.image_url
```

---

## Error Handling

### Common Errors

| Error | Code | Handling |
|-------|------|----------|
| Rate limit | `rate_limit_exceeded` | Retry with backoff |
| Context too long | `context_length_exceeded` | Truncate input |
| Content filter | `content_policy_violation` | Return error to user |
| API unavailable | `api_error` | Retry or fail |

### Retry Strategy

```python
class AIEngine:
    MAX_RETRIES = 3
    BASE_DELAY = 1  # seconds
    
    def _call_with_retry(self, func, *args, **kwargs):
        for attempt in range(self.MAX_RETRIES):
            try:
                return func(*args, **kwargs)
            except RateLimitError:
                delay = self.BASE_DELAY * (2 ** attempt)
                time.sleep(delay)
            except ContentPolicyError:
                raise  # Don't retry policy violations
        raise MaxRetriesExceeded()
```

---

## Configuration

### Per-Account Settings

```python
# In AIIntegrationSettings
openai_api_key = "sk-..."
openai_model = "gpt-4"  # or gpt-4-turbo
image_provider = "dalle"  # or "runware"
dalle_api_key = "sk-..."
runware_api_key = "..."
```

### Model Options

| Model | Use Case | Token Limit |
|-------|----------|-------------|
| `gpt-4` | High quality content | 8,192 |
| `gpt-4-turbo` | Faster, larger context | 128,000 |
| `gpt-3.5-turbo` | Budget option | 4,096 |

---

## Monitoring

### Logging

All AI operations logged with:
- Input parameters (sanitized)
- Output summary
- Token usage
- Latency
- Error details

### Metrics

Tracked via internal logging:
- Operations per day
- Average latency
- Error rate
- Token consumption
- Credit usage
