imp part 3
This commit is contained in:
17
IGNY8-APP.md
17
IGNY8-APP.md
@@ -246,8 +246,21 @@ Stage 7: Generate images → Review queue
|
|||||||
| **Usage** | ✅ Active | `/account/usage` |
|
| **Usage** | ✅ Active | `/account/usage` |
|
||||||
| **AI Models** | ✅ Active (Admin) | `/settings/integration` |
|
| **AI Models** | ✅ Active (Admin) | `/settings/integration` |
|
||||||
| **Help** | ✅ Active | `/help` |
|
| **Help** | ✅ Active | `/help` |
|
||||||
| **Linker** | ⏸️ Disabled | Internal linking (available, disabled by default) |
|
| **SiteBuilder** | ❌ Deprecated | Removed - was for site structure generation |
|
||||||
| **Optimizer** | ⏸️ Disabled | Content optimization (available, disabled by default) |
|
| **Linker** | ⏸️ Phase 2 | Internal linking suggestions (disabled by default) |
|
||||||
|
| **Optimizer** | ⏸️ Phase 2 | Content optimization (disabled by default) |
|
||||||
|
|
||||||
|
### Module Status Details
|
||||||
|
|
||||||
|
| Module | Status | Notes |
|
||||||
|
|--------|--------|-------|
|
||||||
|
| **SiteBuilder** | ❌ Deprecated | Code exists but feature is removed. Marked for cleanup. |
|
||||||
|
| **Linker** | ⏸️ Phase 2 | Feature flag: `linker_enabled`. Available but disabled by default. |
|
||||||
|
| **Optimizer** | ⏸️ Phase 2 | Feature flag: `optimizer_enabled`. Available but disabled by default. |
|
||||||
|
|
||||||
|
To enable Phase 2 modules, update via Django Admin:
|
||||||
|
- `GlobalModuleSettings` (pk=1) for platform-wide settings
|
||||||
|
- `ModuleEnableSettings` for per-account settings
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -591,6 +591,10 @@ class AICore:
|
|||||||
image_url = image_data.get('url')
|
image_url = image_data.get('url')
|
||||||
revised_prompt = image_data.get('revised_prompt')
|
revised_prompt = image_data.get('revised_prompt')
|
||||||
|
|
||||||
|
# Use ModelRegistry for image cost (with fallback to constants)
|
||||||
|
from igny8_core.ai.model_registry import ModelRegistry
|
||||||
|
cost = float(ModelRegistry.calculate_cost(model, num_images=n))
|
||||||
|
if cost == 0:
|
||||||
cost = IMAGE_MODEL_RATES.get(model, 0.040) * n
|
cost = IMAGE_MODEL_RATES.get(model, 0.040) * n
|
||||||
print(f"[AI][{function_name}] Step 5: Image generated successfully")
|
print(f"[AI][{function_name}] Step 5: Image generated successfully")
|
||||||
print(f"[AI][{function_name}] Step 6: Cost: ${cost:.4f}")
|
print(f"[AI][{function_name}] Step 6: Cost: ${cost:.4f}")
|
||||||
@@ -827,15 +831,24 @@ class AICore:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def calculate_cost(self, model: str, input_tokens: int, output_tokens: int, model_type: str = 'text') -> float:
|
def calculate_cost(self, model: str, input_tokens: int, output_tokens: int, model_type: str = 'text') -> float:
|
||||||
"""Calculate cost for API call"""
|
"""Calculate cost for API call using ModelRegistry with fallback to constants"""
|
||||||
|
from igny8_core.ai.model_registry import ModelRegistry
|
||||||
|
|
||||||
if model_type == 'text':
|
if model_type == 'text':
|
||||||
|
cost = float(ModelRegistry.calculate_cost(model, input_tokens=input_tokens, output_tokens=output_tokens))
|
||||||
|
if cost == 0:
|
||||||
|
# Fallback to constants
|
||||||
rates = MODEL_RATES.get(model, {'input': 2.00, 'output': 8.00})
|
rates = MODEL_RATES.get(model, {'input': 2.00, 'output': 8.00})
|
||||||
input_cost = (input_tokens / 1_000_000) * rates['input']
|
input_cost = (input_tokens / 1_000_000) * rates['input']
|
||||||
output_cost = (output_tokens / 1_000_000) * rates['output']
|
output_cost = (output_tokens / 1_000_000) * rates['output']
|
||||||
return input_cost + output_cost
|
return input_cost + output_cost
|
||||||
|
return cost
|
||||||
elif model_type == 'image':
|
elif model_type == 'image':
|
||||||
|
cost = float(ModelRegistry.calculate_cost(model, num_images=1))
|
||||||
|
if cost == 0:
|
||||||
rate = IMAGE_MODEL_RATES.get(model, 0.040)
|
rate = IMAGE_MODEL_RATES.get(model, 0.040)
|
||||||
return rate * 1
|
return rate * 1
|
||||||
|
return cost
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
# Legacy method names for backward compatibility
|
# Legacy method names for backward compatibility
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from igny8_core.auth.models import SiteSectorBaseModel, SeedKeyword
|
from igny8_core.auth.models import SiteSectorBaseModel, SeedKeyword
|
||||||
from igny8_core.common.soft_delete import SoftDeletableModel, SoftDeleteManager
|
from igny8_core.common.soft_delete import SoftDeletableModel, SoftDeleteManager
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Clusters(SoftDeletableModel, SiteSectorBaseModel):
|
class Clusters(SoftDeletableModel, SiteSectorBaseModel):
|
||||||
@@ -40,6 +43,27 @@ class Clusters(SoftDeletableModel, SiteSectorBaseModel):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def soft_delete(self, user=None, reason=None, retention_days=None):
|
||||||
|
"""
|
||||||
|
Override soft_delete to cascade status reset to related Keywords.
|
||||||
|
When a cluster is deleted, its keywords should:
|
||||||
|
- Have their cluster FK set to NULL (handled by SET_NULL)
|
||||||
|
- Have their status reset to 'new' (orphaned keywords)
|
||||||
|
"""
|
||||||
|
# Reset related keywords status to 'new' and clear cluster FK
|
||||||
|
keywords_count = self.keywords.filter(is_deleted=False).update(
|
||||||
|
cluster=None,
|
||||||
|
status='new'
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[Clusters.soft_delete] Cluster {self.id} '{self.name}' cascade: "
|
||||||
|
f"reset {keywords_count} keywords to status='new'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call parent soft_delete
|
||||||
|
super().soft_delete(user=user, reason=reason, retention_days=retention_days)
|
||||||
|
|
||||||
|
|
||||||
class Keywords(SoftDeletableModel, SiteSectorBaseModel):
|
class Keywords(SoftDeletableModel, SiteSectorBaseModel):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -146,5 +146,70 @@ Before implementing any UI element:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: Current Session
|
## 📝 Typography Scale
|
||||||
|
|
||||||
|
Typography tokens are defined in `index.css` and should be used consistently:
|
||||||
|
|
||||||
|
### Title Sizes (for page/section headings)
|
||||||
|
| Token | Size | Line Height | Use Case |
|
||||||
|
|-------|------|-------------|----------|
|
||||||
|
| `--text-title-2xl` | 72px | 90px | Hero sections only |
|
||||||
|
| `--text-title-xl` | 60px | 72px | Landing page headings |
|
||||||
|
| `--text-title-lg` | 48px | 60px | Major section headers |
|
||||||
|
| `--text-title-md` | 36px | 44px | Page titles |
|
||||||
|
| `--text-title-sm` | 30px | 38px | Section subtitles |
|
||||||
|
|
||||||
|
### Theme Sizes (for body text)
|
||||||
|
| Token | Size | Line Height | Use Case |
|
||||||
|
|-------|------|-------------|----------|
|
||||||
|
| `--text-theme-xl` | 20px | 30px | Large body text, intro paragraphs |
|
||||||
|
| `--text-theme-sm` | 14px | 20px | Standard body text, menu items |
|
||||||
|
| `--text-theme-xs` | 12px | 18px | Small text, labels, captions |
|
||||||
|
|
||||||
|
### Usage in Tailwind
|
||||||
|
```tsx
|
||||||
|
// Use Tailwind utilities mapped to tokens
|
||||||
|
<h1 className="text-title-md">Page Title</h1>
|
||||||
|
<p className="text-theme-sm">Body text</p>
|
||||||
|
<span className="text-theme-xs">Caption</span>
|
||||||
|
|
||||||
|
// Or use the custom utility classes
|
||||||
|
<h2 className="text-2xl font-semibold">Section Title</h2>
|
||||||
|
<p className="text-base">Body text</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Font Weights
|
||||||
|
- `font-normal` (400) - Body text
|
||||||
|
- `font-medium` (500) - Labels, menu items
|
||||||
|
- `font-semibold` (600) - Headings, emphasis
|
||||||
|
- `font-bold` (700) - Strong emphasis
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Module Colors
|
||||||
|
|
||||||
|
Module-specific colors are defined in `src/config/colors.config.ts`:
|
||||||
|
|
||||||
|
| Module | Primary Color | Usage |
|
||||||
|
|--------|---------------|-------|
|
||||||
|
| Keywords | `brand-500` (blue) | Icons, progress bars, badges |
|
||||||
|
| Clusters | `purple-500` | Icons, progress bars, badges |
|
||||||
|
| Ideas | `purple-600` | Icons, progress bars, badges |
|
||||||
|
| Tasks | `success-600` (green) | Icons, progress bars, badges |
|
||||||
|
| Content | `success-500` | Icons, progress bars, badges |
|
||||||
|
| Images | `purple-500` | Icons, progress bars, badges |
|
||||||
|
| Automation | `brand-500` | Pipeline cards |
|
||||||
|
| Billing | `warning-500` (amber) | Credit displays |
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { MODULE_COLORS } from '@/config/colors.config';
|
||||||
|
|
||||||
|
// Use in components
|
||||||
|
<div className={MODULE_COLORS.keywords.bg}>Keywords Section</div>
|
||||||
|
<span className={MODULE_COLORS.clusters.text}>Cluster Label</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: December 30, 2025
|
||||||
**Status**: Active Design System Rules
|
**Status**: Active Design System Rules
|
||||||
|
|||||||
@@ -175,7 +175,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@utility menu-item {
|
@utility menu-item {
|
||||||
@apply relative flex items-center w-full gap-3 px-3.5 py-2.5 font-medium rounded-lg text-theme-sm;
|
@apply relative flex items-center w-full gap-3.5 px-4 py-3 font-medium rounded-lg text-theme-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility menu-item-active {
|
@utility menu-item-active {
|
||||||
@@ -188,7 +188,7 @@
|
|||||||
|
|
||||||
/* Menu icon sizing - consistent across sidebar */
|
/* Menu icon sizing - consistent across sidebar */
|
||||||
@utility menu-item-icon-size {
|
@utility menu-item-icon-size {
|
||||||
@apply w-5 h-5 flex-shrink-0;
|
@apply w-6 h-6 flex-shrink-0;
|
||||||
|
|
||||||
/* Force SVG icons to inherit parent size */
|
/* Force SVG icons to inherit parent size */
|
||||||
& svg {
|
& svg {
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
|
|
||||||
/* Dropdown menu items - increased spacing */
|
/* Dropdown menu items - increased spacing */
|
||||||
@utility menu-dropdown-item {
|
@utility menu-dropdown-item {
|
||||||
@apply block px-3 py-2 text-theme-sm font-medium rounded-md transition-colors;
|
@apply block px-3.5 py-2.5 text-theme-sm font-medium rounded-md transition-colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility menu-dropdown-item-active {
|
@utility menu-dropdown-item-active {
|
||||||
|
|||||||
Reference in New Issue
Block a user