Commit d39326be authored by Your Name's avatar Your Name

0.99.36

parent 1c25697e
# AISBF Endpoint Documentation
Generated: 2026-04-20T20:48:14+02:00
---
## Access Level Definitions
| Level | Definition |
|-------|------------|
| **Public** | No authentication required |
| **Database user** | User from the database, both role admin or user |
| **user** | User from database with role user |
| **admin** | User from database with role admin |
| **global admin** | Admin user defined in the `aisbf.json` configuration file |
| **global token** | Tokens created by the global admin to access the global API |
| **user token** | Tokens created by and belonging to a specific database user |
---
## Dashboard Endpoints (UI Access)
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard` | GET | Database user | Main dashboard index |
| `/dashboard/login` | GET, POST | Public | Login page |
| `/dashboard/logout` | GET | Database user | Logout user |
| `/dashboard/signup` | GET, POST | Public (if enabled) | User registration |
| `/dashboard/forgot-password` | GET, POST | Public | Password reset request |
| `/dashboard/reset-password` | GET, POST | Public | Password reset form |
| `/dashboard/verify` | GET | Public | Email verification |
| `/dashboard/verify-email` | GET | Database user | Resend verification email |
| `/dashboard/change-password` | GET, POST | Database user | Change password |
| `/dashboard/change-email` | GET, POST | Database user | Change email address |
| `/dashboard/delete-account` | GET, POST | Database user | Delete user account |
| `/dashboard/profile` | GET, POST | Database user | User profile management |
| `/dashboard/settings` | GET, POST | Database user | User settings |
| `/dashboard/docs` | GET | Database user | API documentation |
| `/dashboard/license` | GET | Database user | License information |
| `/dashboard/about` | GET | Database user | About page |
| `/dashboard/extension/download` | GET | Database user | Browser extension download |
### Configuration Pages
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard/providers` | GET, POST | Database user / Global admin | Provider configuration (auto detects context) |
| `/dashboard/rotations` | GET, POST | Database user / Global admin | Rotation configuration (auto detects context) |
| `/dashboard/autoselect` | GET, POST | Database user / Global admin | Autoselect configuration (auto detects context) |
| `/dashboard/providers/get-models` | POST | Database user / Global admin | Fetch models from provider API |
| `/dashboard/providers/{name}/upload` | POST | Database user / Global admin | Upload provider auth files |
| `/dashboard/providers/{name}/files` | GET | Database user / Global admin | List provider auth files |
| `/dashboard/providers/{name}/files/{file}/download` | GET | Database user / Global admin | Download provider auth file |
| `/dashboard/providers/{name}/auth/check` | GET | Database user / Global admin | Check provider OAuth status |
| `/dashboard/providers/upload-auth-file` | POST | Database user / Global admin | Chunked file upload for provider credentials |
| `/dashboard/providers/upload-auth-file/chunk` | POST | Database user / Global admin | Chunked file upload continuation |
| `/dashboard/user/tokens` | GET, POST, DELETE | Database user | API token management |
### Billing & Subscriptions
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard/pricing` | GET | Public | Pricing plans page |
| `/dashboard/subscription` | GET | Database user | Current subscription status |
| `/dashboard/billing` | GET | Database user | Billing history and payment methods |
| `/dashboard/billing/add-method` | GET, POST | Database user | Add payment method |
| `/dashboard/billing/add-method/paypal/oauth` | GET, POST | Database user | PayPal OAuth initiation |
| `/dashboard/billing/add-method/paypal/callback` | GET, POST | Database user | PayPal OAuth callback |
| `/dashboard/billing/payment-methods/{id}/set-default` | POST | Database user | Set default payment method |
### Database Admin (Role=admin)
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard/users` | GET, POST | admin | User management |
| `/dashboard/users/add` | POST | admin | Create new user |
| `/dashboard/users/{id}/edit` | POST | admin | Edit user |
| `/dashboard/users/{id}/delete` | POST | admin | Delete user |
| `/dashboard/users/{id}/toggle` | POST | admin | Toggle user active status |
| `/dashboard/users/{id}/tier` | POST | admin | Update user tier |
| `/dashboard/users/bulk` | POST | admin | Bulk user operations |
| `/dashboard/analytics` | GET | admin | Analytics dashboard |
### Global Admin (aisbf.json defined)
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard/admin/tiers` | GET | global admin | Pricing tiers management |
| `/dashboard/admin/tiers/create` | GET | global admin | Create new tier |
| `/dashboard/admin/tiers/edit/{id}` | GET | global admin | Edit existing tier |
| `/dashboard/admin/tiers/save` | POST | global admin | Save tier changes |
| `/dashboard/admin/payment-settings` | GET | global admin | Payment system configuration |
| `/dashboard/response-cache/stats` | GET | global admin | Cache statistics |
| `/dashboard/response-cache/clear` | POST | global admin | Clear cache |
| `/dashboard/rate-limits` | GET | global admin | Rate limits dashboard |
| `/dashboard/rate-limits/data` | GET | global admin | Rate limits data API |
| `/dashboard/rate-limits/{provider}/reset` | POST | global admin | Reset provider rate limits |
| `/dashboard/condensation` | GET, POST | global admin | Condensation settings |
| `/dashboard/restart` | POST | global admin | Restart server |
| `/dashboard/test-smtp` | POST | global admin | Test email configuration |
### OAuth2 Authentication
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/dashboard/claude/auth/start` | POST | Database user / Global admin | Start Claude OAuth flow |
| `/dashboard/claude/auth/complete` | POST | Database user / Global admin | Complete Claude OAuth flow |
| `/dashboard/claude/auth/callback-status` | GET | Database user / Global admin | Check OAuth callback status |
| `/dashboard/kilo/auth/start` | POST | Database user / Global admin | Start Kilo OAuth flow |
| `/dashboard/kilo/auth/poll` | POST | Database user / Global admin | Poll Kilo OAuth status |
| `/dashboard/kilo/auth/status` | POST | Database user / Global admin | Kilo auth status |
| `/dashboard/qwen/auth/start` | POST | Database user / Global admin | Start Qwen OAuth flow |
| `/dashboard/qwen/auth/poll` | POST | Database user / Global admin | Poll Qwen OAuth status |
| `/dashboard/qwen/auth/status` | POST | Database user / Global admin | Qwen auth status |
| `/dashboard/codex/auth/start` | POST | Database user / Global admin | Start Codex OAuth flow |
| `/dashboard/codex/auth/poll` | POST | Database user / Global admin | Poll Codex OAuth status |
| `/dashboard/codex/auth/status` | POST | Database user / Global admin | Codex auth status |
| `/dashboard/codex/auth/logout` | POST | Database user / Global admin | Codex auth logout |
| `/dashboard/kilo/auth/logout` | POST | Database user / Global admin | Kilo auth logout |
| `/dashboard/qwen/auth/logout` | POST | Database user / Global admin | Qwen auth logout |
---
## API Endpoints (Programmatic Access)
### Public API
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/v1/models` | GET | Public | List available models |
| `/api/webhooks/stripe` | POST | Public (signed) | Stripe webhook endpoint |
| `/api/webhooks/paypal` | POST | Public (signed) | PayPal webhook endpoint |
### Global Token / Global Admin
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/v1/chat/completions` | POST | global token | OpenAI-compatible chat completions (global) |
| `/api/v1/completions` | POST | global token | Legacy completions endpoint (global) |
| `/api/v1/embeddings` | POST | global token | Embeddings generation (global) |
| `/api/v1/images/generations` | POST | global token | Image generation (global) |
| `/api/v1/audio/transcriptions` | POST | global token | Audio transcription (global) |
| `/api/v1/audio/speech` | POST | global token | Text-to-speech (global) |
| `/api/chat/completions` | POST | global token | Alias for `/api/v1/chat/completions` (global) |
| `/api/embeddings` | POST | global token | Alias for `/api/v1/embeddings` (global) |
| `/api/images/generations` | POST | global token | Alias for `/api/v1/images/generations` (global) |
| `/api/audio/transcriptions` | POST | global token | Alias for `/api/v1/audio/transcriptions` (global) |
| `/api/audio/speech` | POST | global token | Alias for `/api/v1/audio/speech` (global) |
| `/api/providers` | GET | global token | List global providers |
| `/api/{provider_id}/models` | GET | global token | List models for specific global provider |
| `/api/{provider_id}/chat/completions` | POST | global token | Direct global provider access |
| `/api/rotations` | GET | global token | List global rotations |
| `/api/rotations/models` | GET | global token | List global rotation models |
| `/api/rotations/chat/completions` | POST | global token | Global rotation completions |
| `/api/autoselect` | GET | global token | List global autoselect rules |
| `/api/autoselect/models` | GET | global token | List global autoselect models |
| `/api/autoselect/chat/completions` | POST | global token | Global autoselect completions |
### User Token / Database User
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/u/{username}/models` | GET | user token | List user's available models |
| `/api/u/{username}/providers` | GET | user token | List user's providers |
| `/api/u/{username}/rotations` | GET | user token | List user's rotations |
| `/api/u/{username}/rotations/models` | GET | user token | List user's rotation models |
| `/api/u/{username}/autoselects` | GET | user token | List user's autoselect rules |
| `/api/u/{username}/autoselects/models` | GET | user token | List user's autoselect models |
| `/api/u/{username}/chat/completions` | POST | user token | User-specific completions |
| `/api/u/{username}/{config_type}/models` | GET | user token | User-specific config models |
### Billing API
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/subscriptions` | POST | Database user | Create subscription |
| `/api/subscriptions/status` | GET | Database user | Subscription status |
| `/api/subscriptions/upgrade` | POST | Database user | Upgrade subscription |
| `/api/subscriptions/downgrade` | POST | Database user | Downgrade subscription |
| `/api/subscriptions/cancel` | POST | Database user | Cancel subscription |
| `/api/payment-methods` | GET | Database user | List payment methods |
| `/api/payment-methods/stripe` | POST | Database user | Add Stripe payment method |
| `/api/payment-methods/paypal/initiate` | POST | Database user | Initiate PayPal payment method |
| `/api/payment-methods/paypal/complete` | POST | Database user | Complete PayPal payment method |
| `/api/payment-methods/crypto` | POST | Database user | Add crypto payment method |
### Global Admin API
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/admin/tiers` | GET, POST | global admin | Pricing tiers management |
| `/api/admin/tiers/{id}` | GET, PUT, DELETE | global admin | Tier CRUD operations |
| `/api/admin/config/consolidation` | GET, POST | global admin | Consolidation configuration |
| `/api/admin/config/email` | GET, POST | global admin | Email configuration |
| `/api/admin/config/price-sources` | GET, POST | global admin | Price sources configuration |
| `/api/admin/settings/currency` | GET, POST | global admin | Currency settings |
| `/api/admin/settings/encryption-key` | GET, POST | global admin | Encryption key settings |
| `/api/admin/settings/payment-gateways` | GET, POST | global admin | Payment gateways settings |
| `/api/admin/scheduler/status` | GET | global admin | Scheduler status |
| `/api/admin/scheduler/run-job` | POST | global admin | Run scheduler job manually |
| `/api/admin/payment-system/config` | GET | global admin | Payment system configuration |
| `/api/admin/payment-system/status` | GET | global admin | Payment system status |
| `/api/admin/crypto/prices` | GET | global admin | Crypto prices |
| `/api/admin/crypto/btc-prices` | GET | global admin | BTC prices |
| `/api/users/search` | GET | admin | Search users |
### Legacy/Deprecated Endpoints
| Endpoint | Methods | Access Level | Description |
|----------|---------|--------------|-------------|
| `/api/autoselections/models` | GET | global token | Deprecated alias for `/api/autoselect/models` |
| `/api/u/{username}/autoselections/models` | GET | user token | Deprecated alias for `/api/u/{username}/autoselects/models` |
| `/api/proxy/{content_id}` | GET | Database user | Content proxy endpoint |
---
## Special Auto-Context Endpoints
Endpoints marked with `Database user / Global admin` automatically detect context:
- If accessed by `global admin` → operates on global JSON configuration
- If accessed by `Database user` → operates on user-specific database configuration
- No separate endpoints needed for global vs user configuration
All endpoints enforce proper authentication and authorization checks before processing requests.
...@@ -54,7 +54,7 @@ from .auth.qwen import QwenOAuth2 ...@@ -54,7 +54,7 @@ from .auth.qwen import QwenOAuth2
from .handlers import RequestHandler, RotationHandler, AutoselectHandler from .handlers import RequestHandler, RotationHandler, AutoselectHandler
from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model
__version__ = "0.99.35" __version__ = "0.99.36"
__all__ = [ __all__ = [
# Config # Config
"config", "config",
......
...@@ -5570,239 +5570,6 @@ async def dashboard_restart(request: Request): ...@@ -5570,239 +5570,6 @@ async def dashboard_restart(request: Request):
return JSONResponse({"error": f"Failed to reload configuration: {str(e)}"}, status_code=500) return JSONResponse({"error": f"Failed to reload configuration: {str(e)}"}, status_code=500)
# User-specific configuration management routes # User-specific configuration management routes
@app.get("/dashboard/user/providers", response_class=HTMLResponse)
async def dashboard_user_providers(request: Request):
"""User provider management page"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
# Get user-specific providers
user_providers = db.get_user_providers(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_providers.html",
context={
"request": request,
"session": request.session,
"user_providers_json": json.dumps(user_providers),
"user_id": user_id
}
)
@app.post("/dashboard/user/providers")
async def dashboard_user_providers_save(request: Request, provider_name: str = Form(...), provider_config: str = Form(...)):
"""Save user-specific provider configuration"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
# Validate JSON
provider_data = json.loads(provider_config)
# Save to database
db.save_user_provider(user_id, provider_name, provider_data)
return RedirectResponse(url=url_for(request, "/dashboard/user/providers"), status_code=303)
except json.JSONDecodeError as e:
# Reload current providers on error
user_providers = db.get_user_providers(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_providers.html",
context={
"request": request,
"session": request.session,
"user_providers_json": json.dumps(user_providers),
"user_id": user_id,
"error": f"Invalid JSON: {str(e)}"
}
)
@app.delete("/dashboard/user/providers/{provider_name}")
async def dashboard_user_providers_delete(request: Request, provider_name: str):
"""Delete user-specific provider configuration"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return JSONResponse(status_code=401, content={"error": "Not authenticated"})
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
db.delete_user_provider(user_id, provider_name)
return JSONResponse({"message": "Provider deleted successfully"})
except Exception as e:
return JSONResponse(status_code=500, content={"error": str(e)})
# User authentication file management routes
def get_user_auth_files_dir(user_id: int) -> Path:
"""Get the directory for user authentication files"""
auth_files_dir = Path.home() / '.aisbf' / 'user_auth_files' / str(user_id)
auth_files_dir.mkdir(parents=True, exist_ok=True)
return auth_files_dir
@app.post("/dashboard/user/providers/{provider_name}/upload")
async def dashboard_user_provider_upload(
request: Request,
provider_name: str,
file_type: str = Form(...),
file: UploadFile = File(...)
):
"""Upload authentication file for a provider"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return JSONResponse(status_code=401, content={"error": "Not authenticated"})
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
# Validate file type
allowed_types = ['credentials', 'database', 'config', 'kiro_credentials', 'claude_credentials', 'sqlite_db', 'creds_file']
if file_type not in allowed_types:
return JSONResponse(
status_code=400,
content={"error": f"Invalid file type. Allowed: {', '.join(allowed_types)}"}
)
# Get user auth files directory
auth_files_dir = get_user_auth_files_dir(user_id)
# Generate unique filename
import uuid
file_ext = Path(file.filename).suffix if file.filename else '.json'
stored_filename = f"{provider_name}_{file_type}_{uuid.uuid4().hex[:8]}{file_ext}"
file_path = auth_files_dir / stored_filename
# Save file
content = await file.read()
with open(file_path, 'wb') as f:
f.write(content)
# Save metadata to database
file_id = db.save_user_auth_file(
user_id=user_id,
provider_id=provider_name,
file_type=file_type,
original_filename=file.filename or stored_filename,
stored_filename=stored_filename,
file_path=str(file_path),
file_size=len(content),
mime_type=file.content_type
)
return JSONResponse({
"message": "File uploaded successfully",
"file_id": file_id,
"file_path": str(file_path),
"stored_filename": stored_filename
})
except Exception as e:
logger.error(f"Error uploading file: {e}")
return JSONResponse(status_code=500, content={"error": str(e)})
@app.get("/dashboard/user/providers/{provider_name}/files")
async def dashboard_user_provider_files(request: Request, provider_name: str):
"""Get all authentication files for a provider"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return JSONResponse(status_code=401, content={"error": "Not authenticated"})
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
files = db.get_user_auth_files(user_id, provider_name)
return JSONResponse({"files": files})
except Exception as e:
return JSONResponse(status_code=500, content={"error": str(e)})
@app.get("/dashboard/user/providers/{provider_name}/files/{file_type}/download")
async def dashboard_user_provider_file_download(
request: Request,
provider_name: str,
file_type: str
):
"""Download an authentication file"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return JSONResponse(status_code=401, content={"error": "Not authenticated"})
from aisbf.database import get_database
from fastapi.responses import FileResponse
db = DatabaseRegistry.get_config_database()
try:
file_info = db.get_user_auth_file(user_id, provider_name, file_type)
if not file_info:
return JSONResponse(status_code=404, content={"error": "File not found"})
file_path = Path(file_info['file_path'])
if not file_path.exists():
return JSONResponse(status_code=404, content={"error": "File not found on disk"})
return FileResponse(
path=str(file_path),
filename=file_info['original_filename'],
media_type=file_info['mime_type'] or 'application/octet-stream'
)
except Exception as e:
return JSONResponse(status_code=500, content={"error": str(e)})
@app.delete("/dashboard/user/providers/{provider_name}/files/{file_type}")
async def dashboard_user_provider_file_delete(
request: Request,
provider_name: str,
file_type: str
):
"""Delete an authentication file"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return JSONResponse(status_code=401, content={"error": "Not authenticated"})
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database() db = DatabaseRegistry.get_config_database()
try: try:
...@@ -6445,68 +6212,13 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str): ...@@ -6445,68 +6212,13 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
# User-specific rotation management routes # User-specific rotation management routes
@app.get("/dashboard/user/rotations", response_class=HTMLResponse) @app.get("/dashboard/user/rotations", response_class=HTMLResponse)
async def dashboard_user_rotations(request: Request): async def dashboard_user_rotations(request: Request):
"""User rotation management page""" """Redirect to unified rotations endpoint"""
auth_check = require_dashboard_auth(request) return RedirectResponse(url=url_for(request, "/dashboard/rotations"), status_code=301)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
# Get user-specific rotations
user_rotations = db.get_user_rotations(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_rotations.html",
context={
"request": request,
"session": request.session,
"user_rotations_json": json.dumps(user_rotations),
"user_id": user_id
}
)
@app.post("/dashboard/user/rotations") @app.post("/dashboard/user/rotations")
async def dashboard_user_rotations_save(request: Request, rotation_name: str = Form(...), rotation_config: str = Form(...)): async def dashboard_user_rotations_save(request: Request, config: str = Form(...)):
"""Save user-specific rotation configuration""" """Redirect to unified rotations save endpoint"""
auth_check = require_dashboard_auth(request) return await dashboard_rotations_save(request, config)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
# Validate JSON
rotation_data = json.loads(rotation_config)
# Save to database
db.save_user_rotation(user_id, rotation_name, rotation_data)
return RedirectResponse(url=url_for(request, "/dashboard/user/rotations"), status_code=303)
except json.JSONDecodeError as e:
# Reload current rotations on error
user_rotations = db.get_user_rotations(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_rotations.html",
context={
"request": request,
"session": request.session,
"user_rotations_json": json.dumps(user_rotations),
"user_id": user_id,
"error": f"Invalid JSON: {str(e)}"
}
)
@app.delete("/dashboard/user/rotations/{rotation_name}") @app.delete("/dashboard/user/rotations/{rotation_name}")
async def dashboard_user_rotations_delete(request: Request, rotation_name: str): async def dashboard_user_rotations_delete(request: Request, rotation_name: str):
...@@ -6531,68 +6243,13 @@ async def dashboard_user_rotations_delete(request: Request, rotation_name: str): ...@@ -6531,68 +6243,13 @@ async def dashboard_user_rotations_delete(request: Request, rotation_name: str):
# User-specific autoselect management routes # User-specific autoselect management routes
@app.get("/dashboard/user/autoselects", response_class=HTMLResponse) @app.get("/dashboard/user/autoselects", response_class=HTMLResponse)
async def dashboard_user_autoselects(request: Request): async def dashboard_user_autoselects(request: Request):
"""User autoselect management page""" """Redirect to unified autoselect endpoint"""
auth_check = require_dashboard_auth(request) return RedirectResponse(url=url_for(request, "/dashboard/autoselect"), status_code=301)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
# Get user-specific autoselects
user_autoselects = db.get_user_autoselects(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_autoselects.html",
context={
"request": request,
"session": request.session,
"user_autoselects_json": json.dumps(user_autoselects),
"user_id": user_id
}
)
@app.post("/dashboard/user/autoselects") @app.post("/dashboard/user/autoselects")
async def dashboard_user_autoselects_save(request: Request, autoselect_name: str = Form(...), autoselect_config: str = Form(...)): async def dashboard_user_autoselects_save(request: Request, config: str = Form(...)):
"""Save user-specific autoselect configuration""" """Redirect to unified autoselect save endpoint"""
auth_check = require_dashboard_auth(request) return await dashboard_autoselect_save(request, config)
if auth_check:
return auth_check
user_id = request.session.get('user_id')
if not user_id:
return RedirectResponse(url=url_for(request, "/dashboard/login"), status_code=303)
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
try:
# Validate JSON
autoselect_data = json.loads(autoselect_config)
# Save to database
db.save_user_autoselect(user_id, autoselect_name, autoselect_data)
return RedirectResponse(url=url_for(request, "/dashboard/user/autoselects"), status_code=303)
except json.JSONDecodeError as e:
# Reload current autoselects on error
user_autoselects = db.get_user_autoselects(user_id)
return templates.TemplateResponse(
request=request,
name="dashboard/user_autoselects.html",
context={
"request": request,
"session": request.session,
"user_autoselects_json": json.dumps(user_autoselects),
"user_id": user_id,
"error": f"Invalid JSON: {str(e)}"
}
)
@app.delete("/dashboard/user/autoselects/{autoselect_name}") @app.delete("/dashboard/user/autoselects/{autoselect_name}")
async def dashboard_user_autoselects_delete(request: Request, autoselect_name: str): async def dashboard_user_autoselects_delete(request: Request, autoselect_name: str):
...@@ -6731,66 +6388,6 @@ async def dashboard_user_tokens_delete(request: Request, token_id: int): ...@@ -6731,66 +6388,6 @@ async def dashboard_user_tokens_delete(request: Request, token_id: int):
try: try:
db.delete_user_api_token(user_id, token_id) db.delete_user_api_token(user_id, token_id)
return JSONResponse({"message": "Token deleted successfully"})
except Exception as e:
return JSONResponse(status_code=500, content={"error": str(e)})
@app.get("/dashboard/tor/status")
async def dashboard_tor_status(request: Request):
"""Get TOR hidden service status"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
global tor_service
if tor_service:
status = tor_service.get_status()
else:
status = {
'enabled': False,
'connected': False,
'onion_address': None,
'service_id': None,
'control_host': None,
'control_port': None,
'hidden_service_port': None
}
return JSONResponse(status)
@app.get("/dashboard/response-cache")
async def dashboard_response_cache(request: Request):
"""Response cache management page"""
auth_check = require_dashboard_auth(request)
if auth_check:
return auth_check
from aisbf.cache import get_response_cache
try:
cache = get_response_cache()
stats = cache.get_stats()
except Exception as e:
logger.error(f"Error getting response cache stats: {e}")
stats = {
'enabled': False,
'hits': 0,
'misses': 0,
'hit_rate': 0.0,
'size': 0,
'evictions': 0,
'backend': 'unknown',
'error': str(e)
}
return templates.TemplateResponse(
request=request,
name="dashboard/response_cache.html",
context={
"request": request,
"session": request.session,
"stats": stats
} }
) )
......
...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" ...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "aisbf" name = "aisbf"
version = "0.99.35" version = "0.99.36"
description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations" description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations"
readme = "README.md" readme = "README.md"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
......
...@@ -49,7 +49,7 @@ class InstallCommand(_install): ...@@ -49,7 +49,7 @@ class InstallCommand(_install):
setup( setup(
name="aisbf", name="aisbf",
version="0.99.35", version="0.99.36",
author="AISBF Contributors", author="AISBF Contributors",
author_email="stefy@nexlab.net", author_email="stefy@nexlab.net",
description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations", description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations",
......
...@@ -1748,6 +1748,9 @@ async function confirmAddProvider() { ...@@ -1748,6 +1748,9 @@ async function confirmAddProvider() {
}; };
} }
// Add to expanded providers so it automatically expands
expandedProviders.add(key);
cancelAddProvider(); cancelAddProvider();
renderProvidersList(); renderProvidersList();
} }
......
...@@ -1699,6 +1699,9 @@ async function confirmAddProvider() { ...@@ -1699,6 +1699,9 @@ async function confirmAddProvider() {
}; };
} }
// Add to expanded providers so it automatically expands
expandedProviders.add(key);
cancelAddProvider(); cancelAddProvider();
renderProvidersList(); renderProvidersList();
} }
......
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