Other
Docking@Home
English
molecular-docking
drug-discovery
distributed-computing
autodock
boinc
chemistry
biology
agent
computational-chemistry
bioinformatics
gpu-acceleration
distributed-network
decentralized
Instructions to use OpenPeerAI/DockingAtHOME with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Docking@Home
How to use OpenPeerAI/DockingAtHOME with Docking@Home:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| """ | |
| GUI Interface for Docking@HOME | |
| A modern web-based GUI using FastAPI and HTML/JavaScript for molecular docking. | |
| Integrates with AutoDock backend for real molecular docking simulations. | |
| Authors: OpenPeer AI, Riemann Computing Inc., Bleunomics, Andrew Magdy Kamal | |
| """ | |
| import os | |
| import json | |
| import asyncio | |
| from pathlib import Path | |
| from typing import Optional, List, Dict | |
| from datetime import datetime | |
| from fastapi import FastAPI, File, UploadFile, HTTPException, WebSocket, WebSocketDisconnect | |
| from fastapi.responses import HTMLResponse, FileResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel | |
| import uvicorn | |
| # Import the docking server components | |
| from .server import job_manager, initialize_server | |
| # Initialize FastAPI app | |
| app = FastAPI( | |
| title="Docking@HOME", | |
| description="Distributed Molecular Docking Platform", | |
| version="1.0.0" | |
| ) | |
| # Data models | |
| class DockingJobRequest(BaseModel): | |
| num_runs: int = 100 | |
| use_gpu: bool = True | |
| job_name: Optional[str] = None | |
| class JobStatus(BaseModel): | |
| job_id: str | |
| status: str | |
| progress: float | |
| message: str | |
| # Active WebSocket connections | |
| active_websockets: List[WebSocket] = [] | |
| # File upload directory | |
| UPLOAD_DIR = Path("uploads") | |
| UPLOAD_DIR.mkdir(exist_ok=True) | |
| RESULTS_DIR = Path("results") | |
| RESULTS_DIR.mkdir(exist_ok=True) | |
| async def root(): | |
| """Serve the main GUI page""" | |
| html_content = """ | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Docking@HOME - Molecular Docking Platform</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| .header { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 15px; | |
| box-shadow: 0 10px 40px rgba(0,0,0,0.1); | |
| margin-bottom: 30px; | |
| text-align: center; | |
| } | |
| .header h1 { | |
| color: #667eea; | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| } | |
| .header p { | |
| color: #666; | |
| font-size: 1.1em; | |
| } | |
| .authors { | |
| color: #888; | |
| font-size: 0.9em; | |
| margin-top: 10px; | |
| } | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 20px; | |
| } | |
| .card { | |
| background: white; | |
| padding: 25px; | |
| border-radius: 15px; | |
| box-shadow: 0 10px 40px rgba(0,0,0,0.1); | |
| } | |
| .card h2 { | |
| color: #667eea; | |
| margin-bottom: 20px; | |
| font-size: 1.5em; | |
| } | |
| .form-group { | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 8px; | |
| color: #333; | |
| font-weight: 600; | |
| } | |
| input[type="file"], | |
| input[type="number"], | |
| select { | |
| width: 100%; | |
| padding: 12px; | |
| border: 2px solid #e0e0e0; | |
| border-radius: 8px; | |
| font-size: 1em; | |
| transition: border-color 0.3s; | |
| } | |
| input:focus, select:focus { | |
| outline: none; | |
| border-color: #667eea; | |
| } | |
| .checkbox-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| input[type="checkbox"] { | |
| width: 20px; | |
| height: 20px; | |
| cursor: pointer; | |
| } | |
| .btn { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 15px 30px; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 1.1em; | |
| font-weight: 600; | |
| cursor: pointer; | |
| width: 100%; | |
| transition: transform 0.2s, box-shadow 0.2s; | |
| } | |
| .btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4); | |
| } | |
| .btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .job-list { | |
| max-height: 400px; | |
| overflow-y: auto; | |
| } | |
| .job-item { | |
| background: #f8f9fa; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin-bottom: 15px; | |
| border-left: 4px solid #667eea; | |
| } | |
| .job-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 10px; | |
| } | |
| .job-id { | |
| font-weight: 600; | |
| color: #333; | |
| } | |
| .status-badge { | |
| padding: 5px 15px; | |
| border-radius: 20px; | |
| font-size: 0.85em; | |
| font-weight: 600; | |
| } | |
| .status-pending { | |
| background: #ffeaa7; | |
| color: #d63031; | |
| } | |
| .status-running { | |
| background: #74b9ff; | |
| color: #0984e3; | |
| } | |
| .status-completed { | |
| background: #55efc4; | |
| color: #00b894; | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 8px; | |
| background: #e0e0e0; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| margin-top: 10px; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
| transition: width 0.3s ease; | |
| } | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 15px; | |
| margin-top: 20px; | |
| } | |
| .stat-card { | |
| background: #f8f9fa; | |
| padding: 15px; | |
| border-radius: 8px; | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 2em; | |
| font-weight: 700; | |
| color: #667eea; | |
| } | |
| .stat-label { | |
| color: #666; | |
| font-size: 0.9em; | |
| margin-top: 5px; | |
| } | |
| .notification { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: white; | |
| padding: 20px; | |
| border-radius: 8px; | |
| box-shadow: 0 5px 20px rgba(0,0,0,0.2); | |
| display: none; | |
| min-width: 300px; | |
| animation: slideIn 0.3s ease; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| transform: translateX(400px); | |
| opacity: 0; | |
| } | |
| to { | |
| transform: translateX(0); | |
| opacity: 1; | |
| } | |
| } | |
| .notification.success { | |
| border-left: 4px solid #00b894; | |
| } | |
| .notification.error { | |
| border-left: 4px solid #d63031; | |
| } | |
| .footer { | |
| text-align: center; | |
| color: white; | |
| margin-top: 30px; | |
| padding: 20px; | |
| } | |
| .full-width { | |
| grid-column: 1 / -1; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>𧬠Docking@HOME</h1> | |
| <p>Distributed Molecular Docking Platform</p> | |
| <div class="authors"> | |
| OpenPeer AI Β· Riemann Computing Inc. Β· Bleunomics Β· Andrew Magdy Kamal | |
| </div> | |
| </div> | |
| <div class="main-content"> | |
| <div class="card"> | |
| <h2>π€ Submit Docking Job</h2> | |
| <form id="dockingForm"> | |
| <div class="form-group"> | |
| <label>Ligand File (PDBQT)</label> | |
| <input type="file" id="ligandFile" accept=".pdbqt,.pdb" required> | |
| </div> | |
| <div class="form-group"> | |
| <label>Receptor File (PDBQT)</label> | |
| <input type="file" id="receptorFile" accept=".pdbqt,.pdb" required> | |
| </div> | |
| <div class="form-group"> | |
| <label>Number of Runs</label> | |
| <input type="number" id="numRuns" value="100" min="1" max="1000" required> | |
| </div> | |
| <div class="form-group checkbox-group"> | |
| <input type="checkbox" id="useGPU" checked> | |
| <label for="useGPU">Use GPU Acceleration</label> | |
| </div> | |
| <button type="submit" class="btn" id="submitBtn"> | |
| π Start Docking | |
| </button> | |
| </form> | |
| </div> | |
| <div class="card"> | |
| <h2>π Active Jobs</h2> | |
| <div class="job-list" id="jobList"> | |
| <p style="text-align: center; color: #999; padding: 20px;"> | |
| No jobs yet. Submit a docking job to get started! | |
| </p> | |
| </div> | |
| </div> | |
| <div class="card full-width"> | |
| <h2>π System Statistics</h2> | |
| <div class="stats"> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="totalJobs">0</div> | |
| <div class="stat-label">Total Jobs</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="completedJobs">0</div> | |
| <div class="stat-label">Completed</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="avgTime">0s</div> | |
| <div class="stat-label">Avg. Time</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="footer"> | |
| <p>Support: andrew@bleunomics.com | Issues: <a href="https://huggingface.co/OpenPeerAI/DockingAtHOME/discussions" style="color: white;">HuggingFace</a></p> | |
| </div> | |
| </div> | |
| <div class="notification" id="notification"> | |
| <div id="notificationMessage"></div> | |
| </div> | |
| <script> | |
| const API_BASE = window.location.origin; | |
| // WebSocket connection for real-time updates | |
| let ws = null; | |
| function connectWebSocket() { | |
| ws = new WebSocket(`ws://${window.location.host}/ws`); | |
| ws.onmessage = (event) => { | |
| const data = JSON.parse(event.data); | |
| updateJobList(); | |
| updateStats(); | |
| }; | |
| ws.onerror = () => { | |
| setTimeout(connectWebSocket, 5000); | |
| }; | |
| } | |
| // Submit docking job | |
| document.getElementById('dockingForm').addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const ligandFile = document.getElementById('ligandFile').files[0]; | |
| const receptorFile = document.getElementById('receptorFile').files[0]; | |
| const numRuns = document.getElementById('numRuns').value; | |
| const useGPU = document.getElementById('useGPU').checked; | |
| if (!ligandFile || !receptorFile) { | |
| showNotification('Please select both ligand and receptor files', 'error'); | |
| return; | |
| } | |
| const submitBtn = document.getElementById('submitBtn'); | |
| submitBtn.disabled = true; | |
| submitBtn.textContent = 'β³ Uploading...'; | |
| try { | |
| // Upload ligand | |
| const ligandFormData = new FormData(); | |
| ligandFormData.append('file', ligandFile); | |
| const ligandResponse = await fetch(`${API_BASE}/upload`, { | |
| method: 'POST', | |
| body: ligandFormData | |
| }); | |
| const ligandData = await ligandResponse.json(); | |
| // Upload receptor | |
| const receptorFormData = new FormData(); | |
| receptorFormData.append('file', receptorFile); | |
| const receptorResponse = await fetch(`${API_BASE}/upload`, { | |
| method: 'POST', | |
| body: receptorFormData | |
| }); | |
| const receptorData = await receptorResponse.json(); | |
| // Submit job | |
| const jobResponse = await fetch(`${API_BASE}/api/jobs`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| ligand_file: ligandData.filename, | |
| receptor_file: receptorData.filename, | |
| num_runs: parseInt(numRuns), | |
| use_gpu: useGPU | |
| }) | |
| }); | |
| const jobData = await jobResponse.json(); | |
| showNotification(`Job submitted successfully! ID: ${jobData.job_id}`, 'success'); | |
| // Reset form | |
| document.getElementById('dockingForm').reset(); | |
| // Update job list | |
| updateJobList(); | |
| updateStats(); | |
| } catch (error) { | |
| showNotification('Error submitting job: ' + error.message, 'error'); | |
| } finally { | |
| submitBtn.disabled = false; | |
| submitBtn.textContent = 'π Start Docking'; | |
| } | |
| }); | |
| // Update job list | |
| async function updateJobList() { | |
| try { | |
| const response = await fetch(`${API_BASE}/api/jobs`); | |
| const jobs = await response.json(); | |
| const jobList = document.getElementById('jobList'); | |
| if (jobs.length === 0) { | |
| jobList.innerHTML = '<p style="text-align: center; color: #999; padding: 20px;">No jobs yet. Submit a docking job to get started!</p>'; | |
| return; | |
| } | |
| jobList.innerHTML = jobs.map(job => ` | |
| <div class="job-item"> | |
| <div class="job-header"> | |
| <span class="job-id">${job.job_id}</span> | |
| <span class="status-badge status-${job.status}">${job.status.toUpperCase()}</span> | |
| </div> | |
| <div style="font-size: 0.9em; color: #666;"> | |
| <div>Ligand: ${job.ligand_file}</div> | |
| <div>Receptor: ${job.receptor_file}</div> | |
| <div>Runs: ${job.num_runs} | GPU: ${job.use_gpu ? 'Yes' : 'No'}</div> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" style="width: ${job.progress * 100}%"></div> | |
| </div> | |
| <div style="margin-top: 5px; font-size: 0.85em; color: #666;"> | |
| Progress: ${(job.progress * 100).toFixed(1)}% | |
| </div> | |
| </div> | |
| `).join(''); | |
| } catch (error) { | |
| console.error('Error updating job list:', error); | |
| } | |
| } | |
| // Update statistics | |
| async function updateStats() { | |
| try { | |
| const response = await fetch(`${API_BASE}/api/stats`); | |
| const stats = await response.json(); | |
| document.getElementById('totalJobs').textContent = stats.total_jobs; | |
| document.getElementById('completedJobs').textContent = stats.completed_jobs; | |
| document.getElementById('avgTime').textContent = stats.avg_time + 's'; | |
| } catch (error) { | |
| console.error('Error updating stats:', error); | |
| } | |
| } | |
| // Show notification | |
| function showNotification(message, type) { | |
| const notification = document.getElementById('notification'); | |
| const messageElement = document.getElementById('notificationMessage'); | |
| messageElement.textContent = message; | |
| notification.className = `notification ${type}`; | |
| notification.style.display = 'block'; | |
| setTimeout(() => { | |
| notification.style.display = 'none'; | |
| }, 5000); | |
| } | |
| // Initialize | |
| connectWebSocket(); | |
| updateJobList(); | |
| updateStats(); | |
| // Refresh job list every 2 seconds | |
| setInterval(() => { | |
| updateJobList(); | |
| updateStats(); | |
| }, 2000); | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| return HTMLResponse(content=html_content) | |
| async def upload_file(file: UploadFile = File(...)): | |
| """Upload ligand or receptor file""" | |
| try: | |
| file_path = UPLOAD_DIR / file.filename | |
| with open(file_path, "wb") as f: | |
| content = await file.read() | |
| f.write(content) | |
| return {"filename": file.filename, "path": str(file_path)} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def create_job( | |
| ligand_file: str, | |
| receptor_file: str, | |
| num_runs: int = 100, | |
| use_gpu: bool = True, | |
| job_name: Optional[str] = None | |
| ): | |
| """Create a new docking job with real AutoDock integration""" | |
| try: | |
| # Submit job to the docking server | |
| job_id = await job_manager.submit_job( | |
| ligand_file=ligand_file, | |
| receptor_file=receptor_file, | |
| num_runs=num_runs, | |
| use_gpu=use_gpu, | |
| job_name=job_name | |
| ) | |
| # Start broadcasting updates | |
| asyncio.create_task(broadcast_job_updates(job_id)) | |
| return job_manager.get_job(job_id) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_jobs(): | |
| """Get all jobs""" | |
| return job_manager.get_all_jobs() | |
| async def get_job(job_id: str): | |
| """Get specific job""" | |
| job = job_manager.get_job(job_id) | |
| if not job: | |
| raise HTTPException(status_code=404, detail="Job not found") | |
| return job | |
| async def get_stats(): | |
| """Get system statistics""" | |
| return job_manager.get_stats() | |
| async def websocket_endpoint(websocket: WebSocket): | |
| """WebSocket for real-time updates""" | |
| await websocket.accept() | |
| active_websockets.append(websocket) | |
| try: | |
| while True: | |
| data = await websocket.receive_text() | |
| # Echo back or handle commands | |
| await websocket.send_json({"status": "connected"}) | |
| except WebSocketDisconnect: | |
| active_websockets.remove(websocket) | |
| except Exception as e: | |
| if websocket in active_websockets: | |
| active_websockets.remove(websocket) | |
| async def broadcast_job_updates(job_id: str): | |
| """Broadcast job progress to all connected WebSocket clients""" | |
| while True: | |
| await asyncio.sleep(0.5) # Update every 500ms | |
| job = job_manager.get_job(job_id) | |
| if not job: | |
| break | |
| # Send update to all connected clients | |
| for ws in active_websockets[:]: # Copy list to avoid modification during iteration | |
| try: | |
| await ws.send_json({ | |
| "type": "job_update", | |
| "job_id": job_id, | |
| "status": job["status"], | |
| "progress": job["progress"] | |
| }) | |
| except Exception: | |
| # Remove disconnected clients | |
| if ws in active_websockets: | |
| active_websockets.remove(ws) | |
| # Stop broadcasting if job is complete or failed | |
| if job["status"] in ["completed", "failed"]: | |
| break | |
| async def startup_event(): | |
| """Initialize the server on startup""" | |
| await initialize_server() | |
| def start_gui(host: str = "localhost", port: int = 8080): | |
| """Start the GUI server with AutoDock integration""" | |
| print(f""" | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β Docking@HOME GUI Server β | |
| β Real AutoDock Integration with GPU Support β | |
| β β | |
| β π Server: http://{host}:{port} β | |
| β 𧬠AutoDock: Enabled (GPU acceleration supported) β | |
| β π§ Support: andrew@bleunomics.com β | |
| β π€ Issues: https://huggingface.co/OpenPeerAI/DockingAtHOME β | |
| β β | |
| β Open your browser to start docking! β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| """) | |
| uvicorn.run(app, host=host, port=port, log_level="info") | |
| if __name__ == "__main__": | |
| start_gui() | |