credits adn tokens final correct setup

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-20 00:36:23 +00:00
parent e041cb8e65
commit c17b22e927
13 changed files with 1170 additions and 233 deletions

View File

@@ -109,8 +109,8 @@ class CreditUsageLog(AccountBaseModel):
class CreditCostConfig(models.Model):
"""
Configurable credit costs per AI function
Admin-editable alternative to hardcoded constants
Token-based credit pricing configuration.
ALL operations use token-to-credit conversion.
"""
# Operation identification
operation_type = models.CharField(
@@ -120,26 +120,27 @@ class CreditCostConfig(models.Model):
help_text="AI operation type"
)
# Cost configuration
credits_cost = models.IntegerField(
validators=[MinValueValidator(0)],
help_text="Credits required for this operation"
# Token-to-credit ratio (tokens per 1 credit)
tokens_per_credit = models.IntegerField(
default=100,
validators=[MinValueValidator(1)],
help_text="Number of tokens that equal 1 credit (e.g., 100 tokens = 1 credit)"
)
# Unit of measurement
UNIT_CHOICES = [
('per_request', 'Per Request'),
('per_100_words', 'Per 100 Words'),
('per_200_words', 'Per 200 Words'),
('per_item', 'Per Item'),
('per_image', 'Per Image'),
]
# Minimum credits (for very small token usage)
min_credits = models.IntegerField(
default=1,
validators=[MinValueValidator(0)],
help_text="Minimum credits to charge regardless of token usage"
)
unit = models.CharField(
max_length=50,
default='per_request',
choices=UNIT_CHOICES,
help_text="What the cost applies to"
# Price per credit (for revenue reporting)
price_per_credit_usd = models.DecimalField(
max_digits=10,
decimal_places=4,
default=Decimal('0.01'),
validators=[MinValueValidator(Decimal('0.0001'))],
help_text="USD price per credit (for revenue reporting)"
)
# Metadata
@@ -149,6 +150,7 @@ class CreditCostConfig(models.Model):
# Status
is_active = models.BooleanField(default=True, help_text="Enable/disable this operation")
# Audit fields
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -162,10 +164,10 @@ class CreditCostConfig(models.Model):
)
# Change tracking
previous_cost = models.IntegerField(
previous_tokens_per_credit = models.IntegerField(
null=True,
blank=True,
help_text="Cost before last update (for audit trail)"
help_text="Tokens per credit before last update (for audit trail)"
)
# History tracking
@@ -179,20 +181,92 @@ class CreditCostConfig(models.Model):
ordering = ['operation_type']
def __str__(self):
return f"{self.display_name} - {self.credits_cost} credits {self.unit}"
return f"{self.display_name} - {self.tokens_per_credit} tokens/credit"
def save(self, *args, **kwargs):
# Track cost changes
# Track token ratio changes
if self.pk:
try:
old = CreditCostConfig.objects.get(pk=self.pk)
if old.credits_cost != self.credits_cost:
self.previous_cost = old.credits_cost
if old.tokens_per_credit != self.tokens_per_credit:
self.previous_tokens_per_credit = old.tokens_per_credit
except CreditCostConfig.DoesNotExist:
pass
super().save(*args, **kwargs)
class BillingConfiguration(models.Model):
"""
System-wide billing configuration (Singleton).
Global settings for token-credit pricing.
"""
# Default token-to-credit ratio
default_tokens_per_credit = models.IntegerField(
default=100,
validators=[MinValueValidator(1)],
help_text="Default: How many tokens equal 1 credit (e.g., 100)"
)
# Credit pricing
default_credit_price_usd = models.DecimalField(
max_digits=10,
decimal_places=4,
default=Decimal('0.01'),
validators=[MinValueValidator(Decimal('0.0001'))],
help_text="Default price per credit in USD"
)
# Reporting settings
enable_token_based_reporting = models.BooleanField(
default=True,
help_text="Show token metrics in all reports"
)
# Rounding settings
ROUNDING_CHOICES = [
('up', 'Round Up'),
('down', 'Round Down'),
('nearest', 'Round to Nearest'),
]
credit_rounding_mode = models.CharField(
max_length=10,
default='up',
choices=ROUNDING_CHOICES,
help_text="How to round fractional credits"
)
# Audit fields
updated_at = models.DateTimeField(auto_now=True)
updated_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
help_text="Admin who last updated"
)
class Meta:
app_label = 'billing'
db_table = 'igny8_billing_configuration'
verbose_name = 'Billing Configuration'
verbose_name_plural = 'Billing Configuration'
def save(self, *args, **kwargs):
"""Enforce singleton pattern"""
self.pk = 1
super().save(*args, **kwargs)
@classmethod
def get_config(cls):
"""Get or create the singleton config"""
config, created = cls.objects.get_or_create(pk=1)
return config
def __str__(self):
return f"Billing Configuration (1 credit = {self.default_tokens_per_credit} tokens)"
class PlanLimitUsage(AccountBaseModel):
"""
Track monthly usage of plan limits (ideas, words, images, prompts)