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:

""" 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 )