docs & ux improvmeents

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-25 20:31:58 +00:00
parent 90e6e96b2b
commit 4bffede052
247 changed files with 6869 additions and 53517 deletions

View File

@@ -0,0 +1,462 @@
# AI Functions Reference
**Last Verified:** December 25, 2025
---
## Overview
IGNY8's AI engine provides functions for content planning and generation. Located in `backend/igny8_core/ai/`.
**Providers:**
- **OpenAI** - GPT-4 for text, DALL-E 3 for images
- **Runware** - Alternative image generation
---
## Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ AI ENGINE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ AIEngine │───►│ Function │───►│ Provider │ │
│ │ (router) │ │ (logic) │ │ (API) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Functions: │
│ • AutoClusterKeywords │
│ • GenerateContentIdeas │
│ • GenerateContent │
│ • GenerateImages │
│ • OptimizeContent (pending) │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 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()
self.text_provider = self._init_text_provider()
self.image_provider = self._init_image_provider()
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) -> List[ContentImage]:
"""Generate images for content"""
```
---
## 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:** GPT-4
**Credit Cost:** 1 idea credit per operation
---
## 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:** GPT-4
**Credit Cost:** 1 idea credit per idea generated
---
## 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
}
}
```
**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:** GPT-4
**Credit Cost:** 1 content credit per generation
---
## Function: GenerateImages
**Purpose:** Create images for article content
**Input:**
```python
{
"content": {
"title": "10 Essential Python Tips for Beginners",
"body": "<html>...</html>",
"primary_keyword": "python tutorial"
},
"options": {
"count": 3,
"style": "photorealistic", # photorealistic, illustration, diagram
"size": "1024x1024"
}
}
```
**Process:**
1. Analyze content to identify image opportunities
2. Generate prompts for each image
3. Call image provider API
4. 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
},
...
]
}
```
**Prompt Template:** `generate_image_prompts`
**Model:** DALL-E 3 or Runware
**Credit Cost:** 1 image credit per image
---
## 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

517
docs/90-REFERENCE/MODELS.md Normal file
View File

@@ -0,0 +1,517 @@
# Database Models Reference
**Last Verified:** December 25, 2025
---
## Auth Models (`igny8_core/auth/models/`)
### User
```python
class User(AbstractBaseUser, PermissionsMixin):
id = UUIDField(primary_key=True)
email = EmailField(unique=True)
first_name = CharField(max_length=150)
last_name = CharField(max_length=150)
account = ForeignKey(Account, related_name='users')
role = ForeignKey(Group, null=True)
is_active = BooleanField(default=True)
is_staff = BooleanField(default=False)
created_at = DateTimeField(auto_now_add=True)
updated_at = DateTimeField(auto_now=True)
```
**Relations:** Account (many-to-one)
---
### Account
```python
class Account(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
plan = ForeignKey(Plan, null=True)
owner = ForeignKey(User, related_name='owned_accounts')
is_active = BooleanField(default=True)
created_at = DateTimeField(auto_now_add=True)
```
**Relations:** Plan (many-to-one), Users (one-to-many), Sites (one-to-many)
---
### Site
```python
class Site(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
domain = CharField(max_length=255, blank=True)
account = ForeignKey(Account, related_name='sites')
industry = ForeignKey(Industry, null=True)
is_active = BooleanField(default=True)
created_at = DateTimeField(auto_now_add=True)
```
**Relations:** Account (many-to-one), Sectors (one-to-many), Industries (many-to-one)
---
### Sector
```python
class Sector(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
description = TextField(blank=True)
site = ForeignKey(Site, related_name='sectors')
is_active = BooleanField(default=True)
created_at = DateTimeField(auto_now_add=True)
```
**Relations:** Site (many-to-one)
---
### Industry
```python
class Industry(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
description = TextField(blank=True)
```
**Used for:** Default seed keywords, industry-specific prompts
---
## Planner Models (`igny8_core/modules/planner/models.py`)
### Keyword
```python
class Keyword(models.Model):
id = UUIDField(primary_key=True)
keyword = CharField(max_length=255)
site = ForeignKey(Site, related_name='keywords')
sector = ForeignKey(Sector, null=True, related_name='keywords')
cluster = ForeignKey(Cluster, null=True, related_name='keywords')
search_volume = IntegerField(null=True)
difficulty = IntegerField(null=True)
cpc = DecimalField(null=True)
status = CharField(choices=KEYWORD_STATUS) # pending, clustered, used, archived
created_by = ForeignKey(User)
created_at = DateTimeField(auto_now_add=True)
```
**Status Values:**
- `pending` - New, awaiting clustering
- `clustered` - Assigned to a cluster
- `used` - Used in content idea
- `archived` - No longer active
---
### Cluster
```python
class Cluster(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
description = TextField(blank=True)
site = ForeignKey(Site, related_name='clusters')
sector = ForeignKey(Sector, null=True, related_name='clusters')
created_by = ForeignKey(User)
created_at = DateTimeField(auto_now_add=True)
```
**Relations:** Site, Sector, Keywords (one-to-many), ContentIdeas (one-to-many)
---
### ContentIdea
```python
class ContentIdea(models.Model):
id = UUIDField(primary_key=True)
title = CharField(max_length=255)
description = TextField(blank=True)
site = ForeignKey(Site, related_name='ideas')
sector = ForeignKey(Sector, null=True)
cluster = ForeignKey(Cluster, related_name='ideas')
primary_keyword = ForeignKey(Keyword, related_name='primary_ideas')
secondary_keywords = ManyToManyField(Keyword, related_name='secondary_ideas')
status = CharField(choices=IDEA_STATUS) # pending, approved, used, archived
created_at = DateTimeField(auto_now_add=True)
```
---
## Writer Models (`igny8_core/modules/writer/models.py`)
### Task
```python
class Task(models.Model):
id = UUIDField(primary_key=True)
title = CharField(max_length=255)
brief = TextField(blank=True)
site = ForeignKey(Site, related_name='tasks')
sector = ForeignKey(Sector, null=True)
idea = ForeignKey(ContentIdea, null=True, related_name='tasks')
primary_keyword = CharField(max_length=255)
secondary_keywords = JSONField(default=list)
status = CharField(choices=TASK_STATUS) # pending, in_progress, completed, cancelled
priority = CharField(choices=PRIORITY) # low, medium, high
assigned_to = ForeignKey(User, null=True)
due_date = DateField(null=True)
created_by = ForeignKey(User)
created_at = DateTimeField(auto_now_add=True)
```
---
### Content
```python
class Content(models.Model):
id = UUIDField(primary_key=True)
title = CharField(max_length=255)
body = TextField() # HTML content
excerpt = TextField(blank=True)
site = ForeignKey(Site, related_name='content')
sector = ForeignKey(Sector, null=True)
task = ForeignKey(Task, related_name='content')
meta_title = CharField(max_length=255, blank=True)
meta_description = TextField(blank=True)
status = CharField(choices=CONTENT_STATUS) # draft, review, approved, published
word_count = IntegerField(default=0)
created_by = ForeignKey(User)
created_at = DateTimeField(auto_now_add=True)
updated_at = DateTimeField(auto_now=True)
```
**Status Values:**
- `draft` - Initial state after generation
- `review` - Pending human review
- `approved` - Ready for publishing
- `published` - Published to WordPress
---
### ContentImage
```python
class ContentImage(models.Model):
id = UUIDField(primary_key=True)
content = ForeignKey(Content, related_name='images')
url = URLField()
thumbnail_url = URLField(blank=True)
alt_text = CharField(max_length=255)
caption = TextField(blank=True)
is_featured = BooleanField(default=False)
position = IntegerField(default=0)
# AI generation metadata
prompt = TextField(blank=True)
provider = CharField(max_length=50) # dalle, runware
created_at = DateTimeField(auto_now_add=True)
```
---
## Integration Models (`igny8_core/modules/integration/models.py`)
### SiteIntegration
```python
class SiteIntegration(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=255)
site = ForeignKey(Site, related_name='integrations')
integration_type = CharField(max_length=50) # wordpress
# Credentials (encrypted)
url = URLField()
username = CharField(max_length=255)
api_key = CharField(max_length=255) # Application password
# Cached structure
categories = JSONField(default=list)
tags = JSONField(default=list)
authors = JSONField(default=list)
post_types = JSONField(default=list)
# Status
is_active = BooleanField(default=True)
last_sync_at = DateTimeField(null=True)
structure_updated_at = DateTimeField(null=True)
created_at = DateTimeField(auto_now_add=True)
```
---
## Billing Models (`igny8_core/modules/billing/models.py`)
### Plan
```python
class Plan(models.Model):
id = UUIDField(primary_key=True)
name = CharField(max_length=100)
slug = SlugField(unique=True)
idea_credits = IntegerField(default=0)
content_credits = IntegerField(default=0)
image_credits = IntegerField(default=0)
optimization_credits = IntegerField(default=0)
max_sites = IntegerField(default=1)
max_users = IntegerField(default=1)
price_monthly = DecimalField(max_digits=10, decimal_places=2)
price_yearly = DecimalField(max_digits=10, decimal_places=2)
is_active = BooleanField(default=True)
is_internal = BooleanField(default=False)
```
---
### CreditBalance
```python
class CreditBalance(models.Model):
account = ForeignKey(Account, related_name='credit_balances')
site = ForeignKey(Site, null=True, related_name='credit_balances')
idea_credits = IntegerField(default=0)
content_credits = IntegerField(default=0)
image_credits = IntegerField(default=0)
optimization_credits = IntegerField(default=0)
period_start = DateField()
period_end = DateField()
created_at = DateTimeField(auto_now_add=True)
updated_at = DateTimeField(auto_now=True)
```
---
### CreditUsage
```python
class CreditUsage(models.Model):
account = ForeignKey(Account, related_name='credit_usage')
site = ForeignKey(Site, null=True)
user = ForeignKey(User)
credit_type = CharField(max_length=50) # idea, content, image, optimization
amount = IntegerField()
operation = CharField(max_length=100) # generate_content, etc.
related_content_type = ForeignKey(ContentType, null=True)
related_object_id = UUIDField(null=True)
created_at = DateTimeField(auto_now_add=True)
```
---
## System Models (`igny8_core/modules/system/`)
### ModuleEnableSettings
```python
class ModuleEnableSettings(models.Model):
account = OneToOneField(Account, primary_key=True)
planner_enabled = BooleanField(default=True)
writer_enabled = BooleanField(default=True)
linker_enabled = BooleanField(default=False)
optimizer_enabled = BooleanField(default=False)
automation_enabled = BooleanField(default=True)
integration_enabled = BooleanField(default=True)
publisher_enabled = BooleanField(default=True)
```
---
### AIIntegrationSettings
```python
class AIIntegrationSettings(models.Model):
account = ForeignKey(Account, related_name='ai_settings')
# OpenAI
openai_api_key = CharField(max_length=255, blank=True)
openai_model = CharField(max_length=50, default='gpt-4')
# Image generation
image_provider = CharField(max_length=50, default='dalle') # dalle, runware
dalle_api_key = CharField(max_length=255, blank=True)
runware_api_key = CharField(max_length=255, blank=True)
is_validated = BooleanField(default=False)
validated_at = DateTimeField(null=True)
```
---
### PromptTemplate
```python
class PromptTemplate(models.Model):
account = ForeignKey(Account, null=True) # null = system default
prompt_type = CharField(max_length=100) # auto_cluster, generate_ideas, etc.
template = TextField()
variables = JSONField(default=list)
is_active = BooleanField(default=True)
created_at = DateTimeField(auto_now_add=True)
updated_at = DateTimeField(auto_now=True)
```
---
## Publisher Models (`igny8_core/modules/publisher/models.py`)
### PublishingRecord
```python
class PublishingRecord(models.Model):
id = UUIDField(primary_key=True)
content = ForeignKey(Content, related_name='publishing_records')
integration = ForeignKey(SiteIntegration, related_name='publishing_records')
external_id = CharField(max_length=255) # WordPress post ID
external_url = URLField(blank=True)
status = CharField(max_length=50) # pending, published, failed
published_at = DateTimeField(null=True)
created_at = DateTimeField(auto_now_add=True)
```
---
## Automation Models (`igny8_core/modules/automation/models.py`)
### AutomationConfig
```python
class AutomationConfig(models.Model):
site = ForeignKey(Site, related_name='automation_configs')
# Stage limits
clustering_limit = IntegerField(default=10)
ideas_limit = IntegerField(default=10)
content_limit = IntegerField(default=5)
image_limit = IntegerField(default=10)
publish_limit = IntegerField(default=5)
# Timing
delay_between_operations = IntegerField(default=5) # seconds
max_runtime = IntegerField(default=3600) # 1 hour
# Behavior
auto_approve = BooleanField(default=False)
auto_publish = BooleanField(default=False)
stop_on_error = BooleanField(default=True)
is_active = BooleanField(default=True)
```
---
### AutomationRun
```python
class AutomationRun(models.Model):
id = UUIDField(primary_key=True)
site = ForeignKey(Site, related_name='automation_runs')
config = ForeignKey(AutomationConfig)
status = CharField(max_length=50) # pending, running, paused, completed, failed, cancelled
# Progress tracking
current_stage = CharField(max_length=50, blank=True)
items_processed = IntegerField(default=0)
items_total = IntegerField(default=0)
# Timing
started_at = DateTimeField(null=True)
completed_at = DateTimeField(null=True)
# Results
error_message = TextField(blank=True)
started_by = ForeignKey(User)
created_at = DateTimeField(auto_now_add=True)
```
---
## Entity Relationship Overview
```
Account
├── Users (many)
├── Sites (many)
│ ├── Sectors (many)
│ ├── Keywords (many)
│ ├── Clusters (many)
│ ├── ContentIdeas (many)
│ ├── Tasks (many)
│ ├── Content (many)
│ │ └── ContentImages (many)
│ ├── SiteIntegrations (many)
│ │ └── PublishingRecords (many)
│ └── AutomationConfigs (many)
│ └── AutomationRuns (many)
├── Plan (one)
├── CreditBalances (many)
├── CreditUsage (many)
├── ModuleEnableSettings (one)
├── AIIntegrationSettings (many)
└── PromptTemplates (many)
```