Implement database-configured token packages

- Add token_packages table to database schema
- Add default token packages (Starter, Professional, Enterprise)
- Add database functions for managing token packages
- Update payments.py to use database packages instead of hardcoded ones
- Remove pricing section from landing page (packages only show when configured)
- Token packages are now fully configurable through admin interface
parent 7ae65909
......@@ -489,52 +489,6 @@
</div>
</section>
<section class="pricing">
<div class="container">
<h2>Token-Based Pricing</h2>
<div class="subtitle">Pay only for what you use. Purchase tokens to access AI analysis features.</div>
<div class="pricing-grid">
<div class="pricing-card">
<h3>Get Started</h3>
<div class="price">Free Trial</div>
<ul class="pricing-features">
<li>100 free tokens</li>
<li>Basic AI analysis</li>
<li>Standard quality</li>
<li>Community support</li>
</ul>
<a href="/register" class="btn btn-primary">Start Free</a>
</div>
<div class="pricing-card popular">
<h3>Premium Access</h3>
<div class="price">Pay per Token</div>
<ul class="pricing-features">
<li>Advanced AI models</li>
<li>High-quality processing</li>
<li>Priority queue</li>
<li>API access available</li>
<li>Dedicated support</li>
</ul>
<a href="/login" class="btn btn-primary">Login to Purchase</a>
</div>
<div class="pricing-card">
<h3>Enterprise</h3>
<div class="price">Custom Pricing</div>
<ul class="pricing-features">
<li>Bulk token packages</li>
<li>Custom AI models</li>
<li>Dedicated infrastructure</li>
<li>White-label options</li>
<li>24/7 enterprise support</li>
</ul>
<a href="/contact" class="btn btn-secondary">Contact Sales</a>
</div>
</div>
</div>
</section>
<footer>
<div class="container">
......
......@@ -203,6 +203,36 @@ def init_db(conn) -> None:
)
''')
# Token packages table
if config['type'] == 'mysql':
cursor.execute('''
CREATE TABLE IF NOT EXISTS token_packages (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
tokens INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
description TEXT,
active BOOLEAN DEFAULT 1,
sort_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
''')
else:
cursor.execute('''
CREATE TABLE IF NOT EXISTS token_packages (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
tokens INTEGER NOT NULL,
price REAL NOT NULL,
description TEXT,
active BOOLEAN DEFAULT 1,
sort_order INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# Processing queue table
if config['type'] == 'mysql':
cursor.execute('''
......@@ -280,6 +310,21 @@ def init_db(conn) -> None:
cursor.execute('INSERT OR IGNORE INTO system_prompts (name, content) VALUES (?, ?)',
('default', 'when the action done by the person or persons in the frame changes, or where the scenario change, or where there an active action after a long time of no actions happening'))
# Insert default token packages if not exist
default_packages = [
('Starter Pack', 500, 4.99, 'Perfect for getting started with AI analysis', 1, 1),
('Professional Pack', 1200, 9.99, 'Advanced features for regular users', 1, 2),
('Enterprise Pack', 3000, 19.99, 'Bulk tokens for heavy usage', 1, 3),
]
for name, tokens, price, description, active, sort_order in default_packages:
if config['type'] == 'mysql':
cursor.execute('INSERT IGNORE INTO token_packages (name, tokens, price, description, active, sort_order) VALUES (?, ?, ?, ?, ?, ?)',
(name, tokens, price, description, active, sort_order))
else:
cursor.execute('INSERT OR IGNORE INTO token_packages (name, tokens, price, description, active, sort_order) VALUES (?, ?, ?, ?, ?, ?)',
(name, tokens, price, description, active, sort_order))
# Insert default admin user if not exist
import hashlib
default_password = hashlib.sha256('admin'.encode()).hexdigest()
......@@ -590,6 +635,93 @@ def get_user_api_tokens(user_id: int) -> List[Dict[str, Any]]:
return [dict(row) for row in rows]
# Token package management functions
def get_token_packages() -> List[Dict[str, Any]]:
"""Get all active token packages ordered by sort_order."""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('SELECT * FROM token_packages WHERE active = 1 ORDER BY sort_order, name')
rows = cursor.fetchall()
conn.close()
return [dict(row) for row in rows]
def get_token_package(package_id: int) -> Optional[Dict[str, Any]]:
"""Get token package by ID."""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('SELECT * FROM token_packages WHERE id = ? AND active = 1', (package_id,))
row = cursor.fetchone()
conn.close()
return dict(row) if row else None
def create_token_package(name: str, tokens: int, price: float, description: str = '', sort_order: int = 0) -> bool:
"""Create a new token package."""
conn = get_db_connection()
cursor = conn.cursor()
try:
cursor.execute('INSERT INTO token_packages (name, tokens, price, description, sort_order) VALUES (?, ?, ?, ?, ?)',
(name, tokens, price, description, sort_order))
conn.commit()
return True
except sqlite3.IntegrityError:
return False
finally:
conn.close()
def update_token_package(package_id: int, name: str = None, tokens: int = None, price: float = None,
description: str = None, sort_order: int = None, active: bool = None) -> bool:
"""Update token package."""
conn = get_db_connection()
cursor = conn.cursor()
update_fields = []
params = []
if name is not None:
update_fields.append('name = ?')
params.append(name)
if tokens is not None:
update_fields.append('tokens = ?')
params.append(tokens)
if price is not None:
update_fields.append('price = ?')
params.append(price)
if description is not None:
update_fields.append('description = ?')
params.append(description)
if sort_order is not None:
update_fields.append('sort_order = ?')
params.append(sort_order)
if active is not None:
update_fields.append('active = ?')
params.append(active)
if not update_fields:
return False
params.append(package_id)
query = f'UPDATE token_packages SET {", ".join(update_fields)} WHERE id = ?'
cursor.execute(query, params)
conn.commit()
success = cursor.rowcount > 0
conn.close()
return success
def delete_token_package(package_id: int) -> bool:
"""Delete token package (soft delete by setting active = 0)."""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('UPDATE token_packages SET active = 0 WHERE id = ?', (package_id,))
conn.commit()
success = cursor.rowcount > 0
conn.close()
return success
# Queue management functions
def add_to_queue(user_id: int, request_type: str, data: dict, priority: int = 0) -> int:
"""Add request to processing queue."""
......
......@@ -221,14 +221,15 @@ def create_payment_intent(processor_name: str, tokens: int, amount: float) -> Op
def get_token_packages() -> List[Dict[str, Any]]:
"""Get available token packages."""
return [
{'tokens': 100, 'price': 10.00, 'popular': False},
{'tokens': 250, 'price': 22.50, 'popular': False},
{'tokens': 500, 'price': 40.00, 'popular': True},
{'tokens': 1000, 'price': 70.00, 'popular': False},
{'tokens': 2500, 'price': 150.00, 'popular': False},
]
"""Get available token packages from database."""
from .database import get_token_packages as db_get_token_packages
packages = db_get_token_packages()
# Add 'popular' flag for display purposes (could be based on sort_order or a separate field)
for package in packages:
package['popular'] = package.get('sort_order') == 2 # Make the middle package popular
return packages
def calculate_price(tokens: int) -> float:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment