import os
import json
import requests
import gradio as gr
from datetime import datetime
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# API Configuration
API_KEY = os.getenv('StableCogKey', '')
if not API_KEY:
API_KEY = "StableCogKey"
API_HOST = 'https://api.stablecog.com'
# API Endpoints
CREDITS_ENDPOINT = '/v1/credits'
MODELS_ENDPOINT = '/v1/image/generation/models'
CREDITS_URL = f'{API_HOST}{CREDITS_ENDPOINT}'
MODELS_URL = f'{API_HOST}{MODELS_ENDPOINT}'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
def check_credits():
"""Check StableCog credits and return formatted results"""
try:
response = requests.get(CREDITS_URL, headers=headers, timeout=10)
if response.status_code == 200:
res_json = response.json()
# Parse the actual response structure
total_remaining_credits = res_json.get('total_remaining_credits', 0)
credits_list = res_json.get('credits', [])
# Calculate total initial credits from all credit entries
total_initial_credits = 0
total_used_credits = 0
credit_details = []
for credit in credits_list:
credit_type = credit.get('type', {})
initial_amount = credit_type.get('amount', 0)
remaining_amount = credit.get('remaining_amount', 0)
credit_name = credit_type.get('name', 'Unknown')
total_initial_credits += initial_amount
used_credits = initial_amount - remaining_amount
total_used_credits += used_credits
# Store credit details for display
credit_details.append({
'name': credit_name,
'initial': initial_amount,
'remaining': remaining_amount,
'used': used_credits,
'expires': credit.get('expires_at', 'Never'),
'description': credit_type.get('description', '')
})
# Use total_remaining_credits from API or calculate it
if total_remaining_credits == 0 and credits_list:
total_remaining_credits = sum(credit.get('remaining_amount', 0) for credit in credits_list)
# Calculate total credits
total_credits = max(total_initial_credits, total_remaining_credits + total_used_credits)
# Calculate percentage used
if total_credits > 0:
percentage_used = (total_used_credits / total_credits * 100)
else:
percentage_used = 0
# Create formatted output
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")
result = {
"success": True,
"total_credits": total_credits,
"total_remaining_credits": total_remaining_credits,
"total_used_credits": total_used_credits,
"percentage_used": round(percentage_used, 2),
"credit_details": credit_details,
"total_credit_types": len(credits_list),
"timestamp": timestamp,
"raw_data": json.dumps(res_json, indent=2)
}
return result
else:
return {
"success": False,
"error": f"API Error: {response.status_code}",
"message": response.text if response.text else "No response text",
"status_code": response.status_code
}
except requests.exceptions.Timeout:
return {
"success": False,
"error": "Timeout Error",
"message": "The request timed out. Please try again."
}
except requests.exceptions.ConnectionError:
return {
"success": False,
"error": "Connection Error",
"message": "Could not connect to the API. Check your internet connection."
}
except Exception as e:
return {
"success": False,
"error": f"Unexpected Error: {type(e).__name__}",
"message": str(e)
}
def get_available_models():
"""Get available StableCog models"""
try:
response = requests.get(MODELS_URL, headers=headers, timeout=10)
if response.status_code == 200:
res_json = response.json()
models_list = res_json.get('models', [])
# Organize models by type
organized_models = []
for model in models_list:
# Extract model information
model_info = {
'id': model.get('id', ''),
'name': model.get('name', 'Unknown'),
'description': model.get('description', ''),
'type': model.get('type', 'unknown'),
'is_public': model.get('is_public', False),
'is_default': model.get('is_default', False),
'is_community': model.get('is_community', False),
'created_at': model.get('created_at', ''),
'updated_at': model.get('updated_at', '')
}
organized_models.append(model_info)
# Sort models: default/public first, then by name
organized_models.sort(key=lambda x: (
not x['is_default'],
not x['is_public'],
x['name'].lower()
))
# Count by type
model_count = len(organized_models)
public_count = sum(1 for m in organized_models if m['is_public'])
default_count = sum(1 for m in organized_models if m['is_default'])
community_count = sum(1 for m in organized_models if m['is_community'])
result = {
"success": True,
"models": organized_models,
"total_models": model_count,
"public_models": public_count,
"default_models": default_count,
"community_models": community_count,
"raw_data": json.dumps(res_json, indent=2),
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")
}
return result
else:
return {
"success": False,
"error": f"API Error: {response.status_code}",
"message": response.text if response.text else "No response text",
"status_code": response.status_code
}
except requests.exceptions.Timeout:
return {
"success": False,
"error": "Timeout Error",
"message": "The request timed out. Please try again."
}
except requests.exceptions.ConnectionError:
return {
"success": False,
"error": "Connection Error",
"message": "Could not connect to the API. Check your internet connection."
}
except Exception as e:
return {
"success": False,
"error": f"Unexpected Error: {type(e).__name__}",
"message": str(e)
}
def update_display():
"""Update the UI with credit information"""
result = check_credits()
if result["success"]:
# Create a visual progress bar with color coding
percentage = result["percentage_used"]
if percentage < 50:
bar_color = "#4CAF50" # Green
status = "🟢 Good"
status_color = "#4CAF50"
elif percentage < 80:
bar_color = "#FF9800" # Orange
status = "🟡 Moderate"
status_color = "#FF9800"
else:
bar_color = "#F44336" # Red
status = "🔴 Low"
status_color = "#F44336"
# Build credit details HTML
credit_details_html = ""
for i, credit in enumerate(result["credit_details"]):
if credit['remaining'] > 0 or credit['initial'] > 0:
credit_percentage = (credit['used'] / credit['initial'] * 100) if credit['initial'] > 0 else 0
credit_details_html += f"""
{credit['name']}
{credit['remaining']} / {credit['initial']} ⭐
{credit['description']}
"""
if credit_details_html:
credit_details_section = f"""
📊 Credit Breakdown
{credit_details_html}
"""
else:
credit_details_section = ""
html_content = f"""
🎨 StableCog Credit Status
Total Credits:
{result['total_credits']} ⭐
Remaining Credits:
{result['total_remaining_credits']} ⭐
Used Credits:
{result['total_used_credits']} ⭐
Overall Usage:
{result['percentage_used']}%
{result['percentage_used']}%
Status:
{status}
{credit_details_section}
⏰ Last checked: {result['timestamp']} | 📋 Credit types: {result['total_credit_types']}
"""
return html_content, result['raw_data'], result['total_remaining_credits'], result['percentage_used']
else:
# Error display
html_content = f"""
⚠️ API Connection Error
{result.get('error', 'Unknown error')}
{result.get('message', '')}
{'
Status Code: ' + str(result.get('status_code', '')) + '
' if result.get('status_code') else ''}
🔧 Troubleshooting Tips:
- Check if your API key is set in Hugging Face Secrets
- Verify the API key has proper permissions
- Ensure StableCog API is currently available
- Check your internet connection
"""
return html_content, f"Error: {result.get('error', 'Unknown error')}\n\nDetails: {result.get('message', '')}", 0, 0
def display_models():
"""Display available models in a formatted way"""
result = get_available_models()
if result["success"]:
models_html = ""
model_counter = 0
for model in result["models"]:
model_counter += 1
# Determine model type badge
model_type = model['type'].upper() if model['type'] else 'UNKNOWN'
if model['is_community']:
model_type_badge = f"COMMUNITY"
elif model['is_default']:
model_type_badge = f"DEFAULT"
elif model['is_public']:
model_type_badge = f"PUBLIC"
else:
model_type_badge = f"{model_type}"
# Model ID (shortened)
model_id_short = model['id'][:8] + "..." if len(model['id']) > 8 else model['id']
models_html += f"""
#{model_counter}. {model['name']}
{model_type_badge}
ID: {model_id_short}
{model['description'] or 'No description available'}
📅 Created: {model['created_at'][:10] if model['created_at'] else 'Unknown'}
🔄 Updated: {model['updated_at'][:10] if model['updated_at'] else 'Unknown'}
"""
# Create stats section
stats_html = f"""
{result['total_models']}
Total Models
{result['public_models']}
Public Models
{result['default_models']}
Default Models
{result['community_models']}
Community Models
"""
html_content = f"""
🤖 Available StableCog Models
{stats_html}
{models_html}
⏰ Last updated: {result['timestamp']} | 🔄 Refresh to see latest models
"""
return html_content, result['raw_data']
else:
# Error display
html_content = f"""
⚠️ Failed to Load Models
{result.get('error', 'Unknown error')}
{result.get('message', '')}
"""
return html_content, f"Error: {result.get('error', 'Unknown error')}\n\nDetails: {result.get('message', '')}"
def get_recommendation(remaining_credits, percentage_used):
"""Provide recommendations based on credit status"""
if remaining_credits == 0:
return "💸 **No credits remaining.** Please add credits to continue using StableCog services."
elif percentage_used >= 90:
return "🛑 **Critically low credits!** Consider purchasing more credits before starting new projects."
elif percentage_used >= 75:
return "⚠️ **Credits are running low.** You can still do some work, but plan ahead for larger projects."
elif remaining_credits < 10:
return "📝 **Limited credits available.** Good for small tasks, testing, or single images."
elif remaining_credits < 50:
return "✨ **Credits available!** Suitable for several medium-sized projects or batch processing."
else:
return "🚀 **Plenty of credits!** Ready for extensive image generation work and experimentation."
# Create Gradio interface with simplified theme configuration for Gradio 6
# In Gradio 6, theme is set differently or uses default
with gr.Blocks(
title="StableCog Dashboard",
css="""
footer {display: none !important;}
.gradio-container {max-width: 1400px !important;}
.tab-nav {background: rgba(255,255,255,0.1) !important; border-radius: 10px !important; padding: 5px !important;}
.stat-box input {font-weight: bold !important; font-size: 18px !important;}
.recommendation-box textarea {font-size: 16px !important; line-height: 1.5 !important;}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.gradio-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
"""
) as demo:
gr.Markdown("""
# 🎯 StableCog Dashboard
*Monitor your credits and explore available AI models for image generation.*
""")
with gr.Tabs() as tabs:
with gr.Tab("💰 Credits Dashboard", id="credits"):
# Status row
with gr.Row():
with gr.Column(scale=2):
credits_html_output = gr.HTML(label="Credit Status")
with gr.Column(scale=1):
credits_raw_output = gr.Code(
label="📋 Raw API Response",
language="json",
interactive=False,
lines=15
)
# Stats row
with gr.Row():
with gr.Column():
credits_display = gr.Number(
label="Remaining Credits",
interactive=False
)
with gr.Column():
usage_display = gr.Number(
label="Usage Percentage",
interactive=False
)
# Recommendation row
with gr.Row():
recommendation_box = gr.Textbox(
label="🎯 AI Recommendation",
interactive=False,
lines=3
)
# Control row
with gr.Row():
check_credits_btn = gr.Button(
"🔄 Check Credits",
variant="primary"
)
with gr.Tab("🤖 Available Models", id="models"):
with gr.Row():
with gr.Column(scale=2):
models_html_output = gr.HTML(label="Available Models")
with gr.Column(scale=1):
models_raw_output = gr.Code(
label="📋 Raw API Response",
language="json",
interactive=False,
lines=15
)
with gr.Row():
check_models_btn = gr.Button(
"🔄 Refresh Models",
variant="primary"
)
# Instructions and info
with gr.Accordion("📚 How to Use & Setup", open=False):
gr.Markdown("""
### Setting Up on Hugging Face Spaces:
1. **Add your API key as a Secret:**
- Go to your Space's Settings → Secrets
- Add a new secret with:
- Key: `STABLECOG_API_KEY`
- Value: `your_actual_api_key_here`
### Features:
- **💰 Credits Dashboard**: Monitor your credit usage and remaining balance
- **🤖 Available Models**: Browse all StableCog image generation models
- **Smart Recommendations**: Get AI-powered suggestions based on your credits
- **Credit Breakdown**: See detailed breakdown by credit type
### Understanding Credits:
- **Free Credits**: Base credits provided to users
- **Refund Credits**: Credits returned for failed generations
- Each credit type may have different amounts and expiration
""")
gr.Markdown("""
---
*Built with ❤️ for StableCog users | [Report Issues](https://github.com/stability-ai/stablecog/issues)*
""")
# Initialize displays on load
demo.load(
fn=update_display,
inputs=None,
outputs=[credits_html_output, credits_raw_output, credits_display, usage_display]
)
demo.load(
fn=display_models,
inputs=None,
outputs=[models_html_output, models_raw_output]
)
# Connect buttons
def update_all_credits():
html, raw, credits, usage = update_display()
recommendation = get_recommendation(credits, usage)
return html, raw, credits, usage, recommendation
check_credits_btn.click(
fn=update_all_credits,
inputs=None,
outputs=[credits_html_output, credits_raw_output, credits_display, usage_display, recommendation_box]
)
check_models_btn.click(
fn=display_models,
inputs=None,
outputs=[models_html_output, models_raw_output]
)
if __name__ == "__main__":
# For Hugging Face Spaces - Gradio 6 syntax
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True,
debug=False
)