Upload 136 files
Browse files- Dockerfile +32 -18
- app.py +48 -6
- requirements.txt +12 -1
Dockerfile
CHANGED
|
@@ -5,13 +5,13 @@ FROM python:3.10-slim
|
|
| 5 |
# Set working directory
|
| 6 |
WORKDIR /app
|
| 7 |
|
| 8 |
-
#
|
| 9 |
ENV PYTHONUNBUFFERED=1 \
|
| 10 |
PYTHONDONTWRITEBYTECODE=1 \
|
| 11 |
PIP_NO_CACHE_DIR=1 \
|
| 12 |
PIP_DISABLE_PIP_VERSION_CHECK=1
|
| 13 |
|
| 14 |
-
#
|
| 15 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 16 |
gcc \
|
| 17 |
g++ \
|
|
@@ -22,36 +22,50 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 22 |
# Copy requirements first for better layer caching
|
| 23 |
COPY requirements.txt .
|
| 24 |
|
| 25 |
-
#
|
| 26 |
-
#
|
| 27 |
-
RUN pip install --no-cache-dir
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
#
|
| 30 |
RUN pip install --no-cache-dir \
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
"torch>=2.0.0"
|
| 38 |
|
| 39 |
# Copy all application code
|
| 40 |
COPY . .
|
| 41 |
|
| 42 |
# Create necessary directories
|
| 43 |
-
RUN mkdir -p data logs
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
|
| 46 |
# Expose port 7860 (HuggingFace Spaces standard port)
|
| 47 |
EXPOSE 7860
|
| 48 |
|
| 49 |
# Health check endpoint for HuggingFace Spaces
|
| 50 |
-
# مطمئن شو تو FastAPI روت /health رو داری، مثلاً:
|
| 51 |
-
# @app.get("/health") -> {"status": "ok"}
|
| 52 |
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
| 53 |
CMD curl -f http://localhost:7860/health || exit 1
|
| 54 |
|
| 55 |
# Run the FastAPI application with uvicorn
|
| 56 |
-
#
|
| 57 |
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--log-level", "info", "--workers", "1"]
|
|
|
|
| 5 |
# Set working directory
|
| 6 |
WORKDIR /app
|
| 7 |
|
| 8 |
+
# Set environment variables for better Python behavior
|
| 9 |
ENV PYTHONUNBUFFERED=1 \
|
| 10 |
PYTHONDONTWRITEBYTECODE=1 \
|
| 11 |
PIP_NO_CACHE_DIR=1 \
|
| 12 |
PIP_DISABLE_PIP_VERSION_CHECK=1
|
| 13 |
|
| 14 |
+
# Install system dependencies required for building Python packages
|
| 15 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 16 |
gcc \
|
| 17 |
g++ \
|
|
|
|
| 22 |
# Copy requirements first for better layer caching
|
| 23 |
COPY requirements.txt .
|
| 24 |
|
| 25 |
+
# Install Python dependencies with optimizations
|
| 26 |
+
# Split into two steps: core dependencies first, then ML libraries
|
| 27 |
+
RUN pip install --no-cache-dir \
|
| 28 |
+
fastapi==0.104.1 \
|
| 29 |
+
uvicorn[standard]==0.24.0 \
|
| 30 |
+
pydantic==2.5.0 \
|
| 31 |
+
python-multipart==0.0.6 \
|
| 32 |
+
websockets==12.0 \
|
| 33 |
+
SQLAlchemy==2.0.23 \
|
| 34 |
+
APScheduler==3.10.4 \
|
| 35 |
+
aiohttp==3.9.1 \
|
| 36 |
+
requests==2.31.0 \
|
| 37 |
+
httpx \
|
| 38 |
+
python-dotenv==1.0.0 \
|
| 39 |
+
feedparser==6.0.11 \
|
| 40 |
+
gradio==4.14.0 \
|
| 41 |
+
pandas==2.1.4 \
|
| 42 |
+
plotly==5.18.0
|
| 43 |
|
| 44 |
+
# Install HuggingFace ML dependencies separately
|
| 45 |
RUN pip install --no-cache-dir \
|
| 46 |
+
transformers>=4.44.0 \
|
| 47 |
+
datasets>=3.0.0 \
|
| 48 |
+
huggingface_hub>=0.24.0 \
|
| 49 |
+
torch>=2.0.0 --index-url https://download.pytorch.org/whl/cpu \
|
| 50 |
+
sentencepiece>=0.1.99 \
|
| 51 |
+
protobuf>=3.20.0
|
|
|
|
| 52 |
|
| 53 |
# Copy all application code
|
| 54 |
COPY . .
|
| 55 |
|
| 56 |
# Create necessary directories
|
| 57 |
+
RUN mkdir -p data logs
|
| 58 |
+
|
| 59 |
+
# Set proper permissions for data directories
|
| 60 |
+
RUN chmod -R 755 data logs
|
| 61 |
|
| 62 |
# Expose port 7860 (HuggingFace Spaces standard port)
|
| 63 |
EXPOSE 7860
|
| 64 |
|
| 65 |
# Health check endpoint for HuggingFace Spaces
|
|
|
|
|
|
|
| 66 |
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
| 67 |
CMD curl -f http://localhost:7860/health || exit 1
|
| 68 |
|
| 69 |
# Run the FastAPI application with uvicorn
|
| 70 |
+
# Using multiple workers for better performance (adjust based on available resources)
|
| 71 |
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--log-level", "info", "--workers", "1"]
|
app.py
CHANGED
|
@@ -10,12 +10,14 @@ from contextlib import asynccontextmanager
|
|
| 10 |
|
| 11 |
from fastapi import FastAPI, Request
|
| 12 |
from fastapi.middleware.cors import CORSMiddleware
|
| 13 |
-
from fastapi.responses import JSONResponse
|
|
|
|
| 14 |
|
| 15 |
# Import API modules
|
| 16 |
from api.endpoints import router as api_router
|
| 17 |
from api.websocket import router as websocket_router, manager as ws_manager
|
| 18 |
from api.pool_endpoints import router as pool_router
|
|
|
|
| 19 |
|
| 20 |
# Import new WebSocket service routers
|
| 21 |
from api.ws_unified_router import router as ws_unified_router, start_all_websocket_streams
|
|
@@ -168,6 +170,15 @@ async def lifespan(app: FastAPI):
|
|
| 168 |
task_scheduler.start()
|
| 169 |
logger.info("Task scheduler started successfully")
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Log startup summary
|
| 172 |
logger.info("=" * 80)
|
| 173 |
logger.info("Crypto API Monitoring System started successfully")
|
|
@@ -185,17 +196,26 @@ async def lifespan(app: FastAPI):
|
|
| 185 |
logger.info("Shutting down Crypto API Monitoring System...")
|
| 186 |
logger.info("=" * 80)
|
| 187 |
|
| 188 |
-
# 1. Stop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
logger.info("Stopping task scheduler...")
|
| 190 |
task_scheduler.stop()
|
| 191 |
logger.info("Task scheduler stopped")
|
| 192 |
|
| 193 |
-
#
|
| 194 |
logger.info("Stopping WebSocket background tasks...")
|
| 195 |
await ws_manager.stop_background_tasks()
|
| 196 |
logger.info("WebSocket background tasks stopped")
|
| 197 |
|
| 198 |
-
#
|
| 199 |
logger.info("Closing WebSocket connections...")
|
| 200 |
await ws_manager.close_all_connections()
|
| 201 |
logger.info("WebSocket connections closed")
|
|
@@ -309,6 +329,12 @@ app.include_router(
|
|
| 309 |
tags=["Pool Management"]
|
| 310 |
)
|
| 311 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
# Include HF router (if available)
|
| 313 |
if HF_ROUTER_AVAILABLE:
|
| 314 |
try:
|
|
@@ -348,10 +374,26 @@ logger.info("All WebSocket service routers included successfully")
|
|
| 348 |
# Root Endpoints
|
| 349 |
# ============================================================================
|
| 350 |
|
| 351 |
-
@app.get("/", tags=["Root"])
|
| 352 |
async def root():
|
| 353 |
"""
|
| 354 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 355 |
|
| 356 |
Returns:
|
| 357 |
API information and endpoint listing
|
|
|
|
| 10 |
|
| 11 |
from fastapi import FastAPI, Request
|
| 12 |
from fastapi.middleware.cors import CORSMiddleware
|
| 13 |
+
from fastapi.responses import JSONResponse, HTMLResponse, FileResponse
|
| 14 |
+
from fastapi.staticfiles import StaticFiles
|
| 15 |
|
| 16 |
# Import API modules
|
| 17 |
from api.endpoints import router as api_router
|
| 18 |
from api.websocket import router as websocket_router, manager as ws_manager
|
| 19 |
from api.pool_endpoints import router as pool_router
|
| 20 |
+
from api.data_endpoints import router as data_router
|
| 21 |
|
| 22 |
# Import new WebSocket service routers
|
| 23 |
from api.ws_unified_router import router as ws_unified_router, start_all_websocket_streams
|
|
|
|
| 170 |
task_scheduler.start()
|
| 171 |
logger.info("Task scheduler started successfully")
|
| 172 |
|
| 173 |
+
# 7. Start WebSocket data broadcaster
|
| 174 |
+
logger.info("Starting WebSocket data broadcaster...")
|
| 175 |
+
try:
|
| 176 |
+
from api.ws_data_broadcaster import broadcaster
|
| 177 |
+
asyncio.create_task(broadcaster.start_broadcasting())
|
| 178 |
+
logger.info("WebSocket data broadcaster started")
|
| 179 |
+
except Exception as e:
|
| 180 |
+
logger.warning(f"Could not start WebSocket data broadcaster: {e}")
|
| 181 |
+
|
| 182 |
# Log startup summary
|
| 183 |
logger.info("=" * 80)
|
| 184 |
logger.info("Crypto API Monitoring System started successfully")
|
|
|
|
| 196 |
logger.info("Shutting down Crypto API Monitoring System...")
|
| 197 |
logger.info("=" * 80)
|
| 198 |
|
| 199 |
+
# 1. Stop WebSocket data broadcaster
|
| 200 |
+
logger.info("Stopping WebSocket data broadcaster...")
|
| 201 |
+
try:
|
| 202 |
+
from api.ws_data_broadcaster import broadcaster
|
| 203 |
+
await broadcaster.stop_broadcasting()
|
| 204 |
+
logger.info("WebSocket data broadcaster stopped")
|
| 205 |
+
except Exception as e:
|
| 206 |
+
logger.warning(f"Error stopping WebSocket data broadcaster: {e}")
|
| 207 |
+
|
| 208 |
+
# 2. Stop task scheduler
|
| 209 |
logger.info("Stopping task scheduler...")
|
| 210 |
task_scheduler.stop()
|
| 211 |
logger.info("Task scheduler stopped")
|
| 212 |
|
| 213 |
+
# 3. Stop WebSocket background tasks
|
| 214 |
logger.info("Stopping WebSocket background tasks...")
|
| 215 |
await ws_manager.stop_background_tasks()
|
| 216 |
logger.info("WebSocket background tasks stopped")
|
| 217 |
|
| 218 |
+
# 4. Close all WebSocket connections
|
| 219 |
logger.info("Closing WebSocket connections...")
|
| 220 |
await ws_manager.close_all_connections()
|
| 221 |
logger.info("WebSocket connections closed")
|
|
|
|
| 329 |
tags=["Pool Management"]
|
| 330 |
)
|
| 331 |
|
| 332 |
+
# Include Data endpoints router (cryptocurrency data)
|
| 333 |
+
app.include_router(
|
| 334 |
+
data_router,
|
| 335 |
+
tags=["Crypto Data"]
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
# Include HF router (if available)
|
| 339 |
if HF_ROUTER_AVAILABLE:
|
| 340 |
try:
|
|
|
|
| 374 |
# Root Endpoints
|
| 375 |
# ============================================================================
|
| 376 |
|
| 377 |
+
@app.get("/", response_class=HTMLResponse, tags=["Root"])
|
| 378 |
async def root():
|
| 379 |
"""
|
| 380 |
+
Serve the Vidya HTML UI dashboard
|
| 381 |
+
|
| 382 |
+
Returns:
|
| 383 |
+
HTML dashboard interface
|
| 384 |
+
"""
|
| 385 |
+
try:
|
| 386 |
+
with open("index.html", "r", encoding="utf-8") as f:
|
| 387 |
+
return HTMLResponse(content=f.read())
|
| 388 |
+
except Exception as e:
|
| 389 |
+
logger.error(f"Error serving index.html: {e}")
|
| 390 |
+
return HTMLResponse(content=f"<h1>Error loading dashboard</h1><p>{str(e)}</p>", status_code=500)
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
@app.get("/api-info", tags=["Root"])
|
| 394 |
+
async def api_info():
|
| 395 |
+
"""
|
| 396 |
+
API information and available endpoints
|
| 397 |
|
| 398 |
Returns:
|
| 399 |
API information and endpoint listing
|
requirements.txt
CHANGED
|
@@ -16,10 +16,21 @@ fastapi==0.104.1
|
|
| 16 |
uvicorn[standard]==0.24.0
|
| 17 |
pydantic==2.5.0
|
| 18 |
python-multipart==0.0.6
|
| 19 |
-
websockets==
|
| 20 |
|
| 21 |
# Database
|
| 22 |
SQLAlchemy==2.0.23
|
| 23 |
|
| 24 |
# Configuration
|
| 25 |
python-dotenv==1.0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
uvicorn[standard]==0.24.0
|
| 17 |
pydantic==2.5.0
|
| 18 |
python-multipart==0.0.6
|
| 19 |
+
websockets==12.0
|
| 20 |
|
| 21 |
# Database
|
| 22 |
SQLAlchemy==2.0.23
|
| 23 |
|
| 24 |
# Configuration
|
| 25 |
python-dotenv==1.0.0
|
| 26 |
+
|
| 27 |
+
# HuggingFace Integration (required for HF Spaces deployment)
|
| 28 |
+
transformers>=4.44.0
|
| 29 |
+
datasets>=3.0.0
|
| 30 |
+
huggingface_hub>=0.24.0
|
| 31 |
+
torch>=2.0.0
|
| 32 |
+
sentencepiece>=0.1.99
|
| 33 |
+
protobuf>=3.20.0
|
| 34 |
+
|
| 35 |
+
# RSS Feed Parsing
|
| 36 |
+
feedparser==6.0.11
|