Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CatGPT Model Manager</title> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <link href="/static/styles.css" rel="stylesheet"> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <!-- Header --> | |
| <header class="header"> | |
| <div class="container"> | |
| <div class="header-content"> | |
| <div class="logo"> | |
| <i class="fa-solid fa-paw"></i> | |
| <h1>CatGPT Model Manager</h1> | |
| </div> | |
| <div class="header-stats"> | |
| <button class="logout-btn" id="logoutBtn" title="Logout" onclick="modelManager.logout()"> | |
| <i class="fas fa-sign-out-alt"></i> | |
| </button> | |
| <button class="theme-toggle" id="themeToggle" title="Toggle dark mode"> | |
| <i class="fas fa-moon" id="themeIcon"></i> | |
| </button> | |
| <button class="activity-logs-btn" id="activityLogsBtn" title="View activity logs"> | |
| <i class="fa-solid fa-scroll"></i> | |
| </button> | |
| <button class="bot-management-btn" id="botManagementBtn" title="Bot management"> | |
| <i class="fa-solid fa-shield-cat"></i> | |
| </button> | |
| <div class="stat-card"> | |
| <span class="stat-value" id="totalModels">0</span> | |
| <span class="stat-label">Models</span> | |
| </div> | |
| <div class="stat-card"> | |
| <span class="stat-value" id="activeModels">0</span> | |
| <span class="stat-label">Gen Ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="main"> | |
| <div class="container"> | |
| <!-- Category Tabs --> | |
| <div class="tabs"> | |
| <button class="tab-button active" data-category="pony"> | |
| <i class="fas fa-horse"></i> | |
| <span>Pony Models</span> | |
| <span class="badge" id="ponyCount">0</span> | |
| </button> | |
| <button class="tab-button" data-category="illustrious"> | |
| <i class="fas fa-palette"></i> | |
| <span>Illustrious Models</span> | |
| <span class="badge" id="illustriousCount">0</span> | |
| </button> | |
| <button class="tab-button" data-category="sdxl"> | |
| <i class="fas fa-image"></i> | |
| <span>SDXL Models</span> | |
| <span class="badge" id="sdxlCount">0</span> | |
| </button> | |
| </div> | |
| <!-- Tab Content --> | |
| <div class="tab-content"> | |
| <!-- Add Model Form --> | |
| <div class="add-model-section"> | |
| <div class="section-header"> | |
| <h2><i class="fas fa-plus-circle"></i> Add New Model</h2> | |
| </div> | |
| <form class="add-model-form" id="addModelForm"> | |
| <div class="form-row form-row-single"> | |
| <div class="form-group"> | |
| <label for="displayName">Display Name</label> | |
| <input type="text" id="displayName" name="displayName" placeholder="e.g., Pony Diffusion V6" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="urn">URN</label> | |
| <input type="text" id="urn" name="urn" placeholder="e.g., @cf/bytedance/stable-diffusion-xl-lightning" required> | |
| </div> | |
| <div class="form-group form-buttons"> | |
| <label> </label> | |
| <div class="button-group"> | |
| <button type="submit" class="btn btn-primary"> | |
| <i class="fas fa-plus"></i> | |
| Add Model | |
| </button> | |
| <button type="button" class="btn btn-outline" id="browseModelBtn" disabled title="Coming soon when Civitai fixes their shit"> | |
| <i class="fas fa-search"></i> | |
| Browse | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Models List --> | |
| <div class="models-section"> | |
| <div class="section-header"> | |
| <h2><i class="fas fa-list"></i> Models (<span id="currentCategory">Pony</span>)</h2> | |
| </div> | |
| <div class="image-filters"> | |
| <div class="filter-group"> | |
| <label for="modelSortFilter">Sort Models:</label> | |
| <select id="modelSortFilter" class="filter-select"> | |
| <option value="displayName-asc">Display Name (A-Z)</option> | |
| <option value="displayName-desc">Display Name (Z-A)</option> | |
| <option value="generation-yes">Onsite Gen (Yes First)</option> | |
| <option value="generation-no">Onsite Gen (No First)</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label for="sortFilter">Sort Images:</label> | |
| <select id="sortFilter" class="filter-select"> | |
| <option value="Most Reactions">Most Reactions</option> | |
| <option value="Most Comments">Most Comments</option> | |
| <option value="Newest">Newest</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label for="nsfwFilter">NSFW:</label> | |
| <select id="nsfwFilter" class="filter-select"> | |
| <option value="None">None</option> | |
| <option value="Soft">Soft</option> | |
| <option value="Mature">Mature</option> | |
| <option value="X">X</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label for="periodFilter">Period:</label> | |
| <select id="periodFilter" class="filter-select"> | |
| <option value="AllTime">All Time</option> | |
| <option value="Year">Year</option> | |
| <option value="Month">Month</option> | |
| <option value="Week">Week</option> | |
| <option value="Day">Day</option> | |
| </select> | |
| </div> | |
| <button class="btn btn-outline btn-icon" id="refreshBtn" title="Refresh models"> | |
| <i class="fas fa-sync-alt"></i> | |
| </button> | |
| <button class="btn btn-danger" id="bulkDeleteBtn" title="Delete all models that don't support generation"> | |
| <i class="fas fa-trash-alt"></i> | |
| Delete No-Gen | |
| </button> | |
| </div> | |
| <div class="models-grid" id="modelsGrid"> | |
| <!-- Models will be loaded here --> | |
| </div> | |
| <div class="empty-state" id="emptyState" style="display: none;"> | |
| <i class="fas fa-inbox"></i> | |
| <h3>No models found</h3> | |
| <p>Add your first model using the form above.</p> | |
| </div> | |
| </div> | |
| <!-- Activity Logs Section --> | |
| <div class="logs-section" id="logsSection" style="display: none;"> | |
| <div class="section-header"> | |
| <h2><i class="fa-solid fa-scroll"></i> Activity Logs</h2> | |
| <div class="logs-controls"> | |
| <select id="logFilter" class="filter-select"> | |
| <option value="all">All Actions</option> | |
| <option value="added">Added</option> | |
| <option value="edited">Edited</option> | |
| <option value="deleted">Deleted</option> | |
| <option value="bulk_deleted">Bulk Deleted</option> | |
| </select> | |
| <select id="categoryLogFilter" class="filter-select"> | |
| <option value="all">All Categories</option> | |
| <option value="pony">Pony</option> | |
| <option value="illustrious">Illustrious</option> | |
| <option value="sdxl">SDXL</option> | |
| </select> | |
| <button class="btn btn-outline" id="refreshLogsBtn"> | |
| <i class="fas fa-sync-alt"></i> | |
| Refresh | |
| </button> | |
| </div> | |
| </div> | |
| <div class="logs-table-container"> | |
| <table class="logs-table" id="logsTable"> | |
| <thead> | |
| <tr> | |
| <th>Timestamp</th> | |
| <th>Action</th> | |
| <th>Category</th> | |
| <th>Display Name</th> | |
| <th>URN</th> | |
| <th>URL</th> | |
| </tr> | |
| </thead> | |
| <tbody id="logsTableBody"> | |
| <!-- Logs will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="empty-state" id="emptyLogsState" style="display: none;"> | |
| <i class="fas fa-history"></i> | |
| <h3>No activity logs found</h3> | |
| <p>Model actions will appear here once they occur.</p> | |
| </div> | |
| </div> | |
| <!-- Bot Management Section --> | |
| <div class="management-section" id="managementSection" style="display: none;"> | |
| <div class="section-header"> | |
| <h2><i class="fas fa-cogs"></i> Discord Bot Management</h2> | |
| </div> | |
| <!-- Configuration Section --> | |
| <div class="config-section"> | |
| <div class="config-card"> | |
| <div class="config-header"> | |
| <h3><i class="fas fa-cog"></i> Discord Bot Configuration</h3> | |
| </div> | |
| <div class="config-body"> | |
| <p>Configure Discord bot management API (stored securely in Firebase):</p> | |
| <div class="config-form"> | |
| <label class="config-label">Bot API URL:</label> | |
| <input type="url" id="botApiUrlInput" placeholder="http://YOUR_BOT_IP:8080" class="api-url-input"> | |
| </div> | |
| <div class="config-form"> | |
| <label class="config-label">Discord Admin Key:</label> | |
| <input type="password" id="discordAdminKeyInput" placeholder="Enter Discord admin key" class="api-url-input"> | |
| </div> | |
| <div class="config-form"> | |
| <button class="btn btn-outline" id="testBotApiUrl"> | |
| <i class="fas fa-wifi"></i> | |
| Test and Save | |
| </button> | |
| </div> | |
| <div class="config-status" id="configStatus"> | |
| <span class="status-text">Not configured</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="management-controls"> | |
| <div class="management-card"> | |
| <div class="card-header"> | |
| <h3><i class="fas fa-power-off"></i> Load Models and Restart Bot</h3> | |
| </div> | |
| <div class="card-body"> | |
| <p>Restart the Discord bot to reload all model configurations and apply changes.</p> | |
| <button class="btn btn-danger management-btn" id="restartBotBtn"> | |
| <i class="fas fa-power-off"></i> | |
| Load Models and Restart Bot | |
| </button> | |
| <div class="status-indicator" id="botStatus"> | |
| <span class="status-text">Ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="management-card"> | |
| <div class="card-header"> | |
| <h3><i class="fas fa-info-circle"></i> Bot Status</h3> | |
| </div> | |
| <div class="card-body"> | |
| <p>Check current Discord bot connection and Firebase status.</p> | |
| <button class="btn btn-outline management-btn" id="checkStatusBtn"> | |
| <i class="fas fa-info-circle"></i> | |
| Check Status | |
| </button> | |
| <div class="status-display" id="statusDisplay"> | |
| <div class="status-item"> | |
| <span class="status-label">Bot Connected:</span> | |
| <span class="status-value" id="botConnected">Unknown</span> | |
| </div> | |
| <div class="status-item"> | |
| <span class="status-label">Firebase Status:</span> | |
| <span class="status-value" id="firebaseStatus">Unknown</span> | |
| </div> | |
| <div class="status-item"> | |
| <span class="status-label">Last Check:</span> | |
| <span class="status-value" id="lastCheck">Never</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="management-info"> | |
| <div class="info-card"> | |
| <h4><i class="fas fa-lightbulb"></i> Usage Instructions</h4> | |
| <ul> | |
| <li><strong>Load Models and Restart Bot:</strong> Use this after adding/editing models to reload all configurations and apply changes.</li> | |
| <li><strong>Check Status:</strong> Monitor bot health and Firebase connectivity.</li> | |
| </ul> | |
| </div> | |
| <div class="info-card"> | |
| <h4><i class="fas fa-terminal"></i> Alternative Commands</h4> | |
| <p>You can also use this Discord slash command directly:</p> | |
| <code>/restart_bot</code> - Restart the bot | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Loading Overlay --> | |
| <div class="loading-overlay" id="loadingOverlay"> | |
| <div class="loading-spinner"> | |
| <i class="fas fa-spinner fa-spin"></i> | |
| <span>Loading...</span> | |
| </div> | |
| </div> | |
| <!-- Toast Notifications --> | |
| <div class="toast-container" id="toastContainer"></div> | |
| <!-- Edit Model Modal --> | |
| <div class="modal-overlay" id="modalOverlay"> | |
| <div class="modal"> | |
| <div class="modal-header"> | |
| <h3><i class="fas fa-edit"></i> Edit Model</h3> | |
| <button class="modal-close" id="modalClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="modal-body"> | |
| <form id="editModelForm"> | |
| <div class="form-group"> | |
| <label for="editDisplayName">Display Name</label> | |
| <input type="text" id="editDisplayName" name="displayName" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="editUrn">URN</label> | |
| <input type="text" id="editUrn" name="urn" required> | |
| </div> | |
| </form> | |
| </div> | |
| <div class="modal-footer"> | |
| <button class="btn btn-outline" id="modalCancel">Cancel</button> | |
| <button class="btn btn-primary" id="modalSave"> | |
| <i class="fas fa-save"></i> | |
| Save Changes | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Browse Models Modal --> | |
| <div class="modal-overlay" id="browseModelsModal"> | |
| <div class="modal modal-large"> | |
| <div class="modal-header"> | |
| <h3><i class="fas fa-search"></i> Browse Models</h3> | |
| <button class="modal-close" id="browseModalsClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="modal-body"> | |
| <div class="browse-controls"> | |
| <div class="search-filters"> | |
| <div class="filter-group"> | |
| <input type="text" id="modelSearchInput" placeholder="Search models..." class="search-input"> | |
| </div> | |
| <div class="filter-group"> | |
| <select id="sortModelsSelect" class="filter-select"> | |
| <option value="Newest">Newest</option> | |
| <option value="Most Downloaded">Most Downloaded</option> | |
| <option value="Highest Rated">Highest Rated</option> | |
| <option value="Most Liked">Most Liked</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <select id="nsfwLevelSelect" class="filter-select"> | |
| <option value="None">SFW Only</option> | |
| <option value="Soft">Include Soft</option> | |
| <option value="Mature">Include Mature</option> | |
| <option value="X">Include All</option> | |
| </select> | |
| </div> | |
| <button class="btn btn-primary" id="searchModelsBtn"> | |
| <i class="fas fa-search"></i> | |
| Search | |
| </button> | |
| </div> | |
| </div> | |
| <div class="browse-results"> | |
| <div class="loading-message" id="browseLoading" style="display: none;"> | |
| <i class="fas fa-spinner fa-spin"></i> | |
| <span>Loading models...</span> | |
| </div> | |
| <div class="browse-models-grid" id="browseModelsGrid"> | |
| <!-- Models will be loaded here --> | |
| </div> | |
| <div class="browse-pagination" id="browsePagination" style="display: none;"> | |
| <button class="btn btn-outline" id="prevPageBtn" disabled> | |
| <i class="fas fa-chevron-left"></i> | |
| Previous | |
| </button> | |
| <span class="page-info" id="pageInfo">Page 1 of 1</span> | |
| <button class="btn btn-outline" id="nextPageBtn"> | |
| Next | |
| <i class="fas fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| <div class="empty-browse-state" id="emptyBrowseState" style="display: none;"> | |
| <i class="fas fa-search"></i> | |
| <h3>No models found</h3> | |
| <p>Try adjusting your search criteria.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Login Modal --> | |
| <div class="modal-overlay" id="loginModal"> | |
| <div class="modal"> | |
| <div class="modal-header"> | |
| <h3><i class="fas fa-lock"></i> Admin Login</h3> | |
| <button class="modal-close" id="loginModalClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="modal-body"> | |
| <form id="loginForm"> | |
| <div class="form-group"> | |
| <label for="adminKey">Admin Key</label> | |
| <input type="password" id="adminKey" name="adminKey" required placeholder="Enter admin key"> | |
| </div> | |
| <div id="loginError" class="error-message" style="display: none;"></div> | |
| </form> | |
| </div> | |
| <div class="modal-footer"> | |
| <button class="btn btn-primary" id="loginSubmit"> | |
| <i class="fas fa-sign-in-alt"></i> | |
| Login | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <footer class="app-footer"> | |
| <p>For aRfy's Cat Bot</p> | |
| </footer> | |
| <script src="/static/app.js"></script> | |
| </body> | |
| </html> |