Spaces:
Running
Running
| # Browser-Only Version (No User Authentication) | |
| # Use Python 3.11 slim image for better compatibility | |
| FROM python:3.11-slim | |
| # Set environment variables | |
| ENV PYTHONUNBUFFERED=1 | |
| ENV DEBIAN_FRONTEND=noninteractive | |
| ENV PORT=7860 | |
| # Install system dependencies | |
| RUN apt-get update && apt-get install -y \ | |
| git \ | |
| libmagic1 \ | |
| libmagic-dev \ | |
| file \ | |
| gcc \ | |
| g++ \ | |
| libc6-dev \ | |
| libffi-dev \ | |
| libjpeg-dev \ | |
| libpng-dev \ | |
| libtiff-dev \ | |
| libwebp-dev \ | |
| zlib1g-dev \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Set work directory | |
| WORKDIR /app | |
| # Clone the repository | |
| RUN git clone https://github.com/wjbmattingly/VLAMy.git . | |
| # Install Python dependencies | |
| RUN pip install --no-cache-dir -r requirements.txt | |
| # Create necessary directories | |
| RUN mkdir -p /app/media/imports /app/staticfiles /app/logs | |
| # Create custom settings for no-auth mode | |
| RUN echo 'from .settings import *\n\ | |
| \n\ | |
| # Disable authentication requirements but keep auth apps for model dependencies\n\ | |
| REST_FRAMEWORK = {\n\ | |
| "DEFAULT_AUTHENTICATION_CLASSES": [],\n\ | |
| "DEFAULT_PERMISSION_CLASSES": [\n\ | |
| "rest_framework.permissions.AllowAny",\n\ | |
| ],\n\ | |
| "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",\n\ | |
| "PAGE_SIZE": 20,\n\ | |
| }\n\ | |
| \n\ | |
| # Use in-memory database for simplicity\n\ | |
| DATABASES = {\n\ | |
| "default": {\n\ | |
| "ENGINE": "django.db.backends.sqlite3",\n\ | |
| "NAME": ":memory:",\n\ | |
| }\n\ | |
| }\n\ | |
| \n\ | |
| # Enhanced cache settings for browser-only mode\n\ | |
| CACHES = {\n\ | |
| "default": {\n\ | |
| "BACKEND": "django.core.cache.backends.locmem.LocMemCache",\n\ | |
| "LOCATION": "vlamy-cache",\n\ | |
| "TIMEOUT": 86400, # 24 hours\n\ | |
| "OPTIONS": {\n\ | |
| "MAX_ENTRIES": 1000,\n\ | |
| }\n\ | |
| }\n\ | |
| }\n\ | |
| \n\ | |
| # Keep auth middleware but disable auth requirements\n\ | |
| MIDDLEWARE = [\n\ | |
| "corsheaders.middleware.CorsMiddleware",\n\ | |
| "django.middleware.security.SecurityMiddleware",\n\ | |
| "django.contrib.sessions.middleware.SessionMiddleware",\n\ | |
| "django.middleware.common.CommonMiddleware",\n\ | |
| "django.middleware.csrf.CsrfViewMiddleware",\n\ | |
| "django.contrib.auth.middleware.AuthenticationMiddleware",\n\ | |
| "django.contrib.messages.middleware.MessageMiddleware",\n\ | |
| # Removed XFrameOptionsMiddleware to allow iframe embedding\n\ | |
| ]\n\ | |
| \n\ | |
| # Keep all apps installed to avoid model dependency issues\n\ | |
| INSTALLED_APPS = [\n\ | |
| "django.contrib.admin",\n\ | |
| "django.contrib.auth",\n\ | |
| "django.contrib.contenttypes",\n\ | |
| "django.contrib.sessions",\n\ | |
| "django.contrib.messages",\n\ | |
| "django.contrib.staticfiles",\n\ | |
| "rest_framework",\n\ | |
| "rest_framework.authtoken",\n\ | |
| "corsheaders",\n\ | |
| "ocr_app",\n\ | |
| ]\n\ | |
| \n\ | |
| # Allow all CORS origins for browser-only mode\n\ | |
| CORS_ALLOW_ALL_ORIGINS = True\n\ | |
| CORS_ALLOW_CREDENTIALS = False\n\ | |
| \n\ | |
| # Static files configuration for no-auth mode\n\ | |
| import os\n\ | |
| STATIC_URL = "/static/"\n\ | |
| STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")\n\ | |
| STATICFILES_DIRS = [\n\ | |
| os.path.join(BASE_DIR, "static"),\n\ | |
| ]\n\ | |
| \n\ | |
| # Media files configuration\n\ | |
| MEDIA_URL = "/media/"\n\ | |
| MEDIA_ROOT = os.path.join(BASE_DIR, "media")\n\ | |
| \n\ | |
| # Enable static file serving in development\n\ | |
| DEBUG = True\n\ | |
| \n\ | |
| # Session settings for browser storage\n\ | |
| SESSION_ENGINE = "django.contrib.sessions.backends.cache"\n\ | |
| SESSION_CACHE_ALIAS = "default"\n\ | |
| SESSION_COOKIE_AGE = 86400 # 24 hours\n\ | |
| \n\ | |
| # Disable file logging to avoid permission issues\n\ | |
| LOGGING = {\n\ | |
| "version": 1,\n\ | |
| "disable_existing_loggers": False,\n\ | |
| "handlers": {\n\ | |
| "console": {\n\ | |
| "level": "INFO",\n\ | |
| "class": "logging.StreamHandler",\n\ | |
| },\n\ | |
| },\n\ | |
| "loggers": {\n\ | |
| "ocr_app": {\n\ | |
| "handlers": ["console"],\n\ | |
| "level": "INFO",\n\ | |
| "propagate": True,\n\ | |
| },\n\ | |
| },\n\ | |
| }\n\ | |
| \n\ | |
| # Create anonymous user middleware reference\n\ | |
| MIDDLEWARE.insert(0, "vlamy_ocr.middleware.AnonymousUserMiddleware")\n\ | |
| \n\ | |
| # Settings for HuggingFace Spaces iframe embedding\n\ | |
| X_FRAME_OPTIONS = "ALLOWALL" # Allow iframe embedding\n\ | |
| SECURE_CROSS_ORIGIN_OPENER_POLICY = None\n\ | |
| SECURE_REFERRER_POLICY = "same-origin"\n\ | |
| \n\ | |
| # Additional security settings for iframe embedding\n\ | |
| SECURE_CONTENT_TYPE_NOSNIFF = False\n\ | |
| SECURE_BROWSER_XSS_FILTER = False\n\ | |
| \n\ | |
| # Allow HuggingFace Spaces in CSP\n\ | |
| CSP_FRAME_ANCESTORS = ["*"]\n\ | |
| CSP_DEFAULT_SRC = ["*"]\n\ | |
| \n\ | |
| # Disable Django security warnings for iframe embedding\n\ | |
| import warnings\n\ | |
| warnings.filterwarnings("ignore", module="django.security")\n\ | |
| \n\ | |
| ' > /app/vlamy_ocr/settings_no_auth.py | |
| # Create a custom URL configuration for no-auth mode | |
| RUN echo 'from django.urls import path, include\n\ | |
| from django.conf import settings\n\ | |
| from django.conf.urls.static import static\n\ | |
| from django.views.generic import TemplateView\n\ | |
| from django.contrib.staticfiles.urls import staticfiles_urlpatterns\n\ | |
| import os\n\ | |
| \n\ | |
| urlpatterns = [\n\ | |
| # API endpoints (no auth required - permissions handled by settings)\n\ | |
| path("api/", include("ocr_app.urls")),\n\ | |
| \n\ | |
| # Frontend routes (single-page application)\n\ | |
| path("", TemplateView.as_view(template_name="index.html"), name="home"),\n\ | |
| path("app/", TemplateView.as_view(template_name="index.html"), name="app"),\n\ | |
| ]\n\ | |
| \n\ | |
| # Always serve static and media files (essential for no-auth mode)\n\ | |
| urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)\n\ | |
| urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\ | |
| urlpatterns += staticfiles_urlpatterns()\n\ | |
| \n\ | |
| # Debug info\n\ | |
| print(f"Static URL: {settings.STATIC_URL}")\n\ | |
| print(f"Static Root: {settings.STATIC_ROOT}")\n\ | |
| static_dirs = getattr(settings, "STATICFILES_DIRS", [])\n\ | |
| print(f"Static Dirs: {static_dirs}")\n\ | |
| ' > /app/vlamy_ocr/urls_no_auth.py | |
| # Ensure static directories exist and collect static files | |
| RUN mkdir -p /app/static /app/staticfiles && \ | |
| DJANGO_SETTINGS_MODULE=vlamy_ocr.settings_no_auth python manage.py collectstatic --noinput --verbosity=2 | |
| # Replace the main urls.py with no-auth version at build time | |
| RUN cp /app/vlamy_ocr/urls_no_auth.py /app/vlamy_ocr/urls.py | |
| # Create anonymous user middleware for no-auth mode | |
| RUN echo 'import os\n\ | |
| from django.contrib.auth.models import User, AnonymousUser\n\ | |
| from django.core.management import execute_from_command_line\n\ | |
| from django.db import connection\n\ | |
| from django.apps import apps\n\ | |
| \n\ | |
| class AnonymousUserMiddleware:\n\ | |
| """Middleware that automatically handles migrations and creates an anonymous user for all requests"""\n\ | |
| \n\ | |
| def __init__(self, get_response):\n\ | |
| self.get_response = get_response\n\ | |
| self._anonymous_user = None\n\ | |
| self._migrations_applied = False\n\ | |
| self._setup_complete = False\n\ | |
| \n\ | |
| def _ensure_migrations_and_user(self):\n\ | |
| """Ensure migrations are applied and anonymous user exists"""\n\ | |
| if self._setup_complete:\n\ | |
| return\n\ | |
| \n\ | |
| try:\n\ | |
| # Check if migrations need to be applied\n\ | |
| if not self._migrations_applied:\n\ | |
| print("Applying database migrations...")\n\ | |
| os.environ.setdefault("DJANGO_SETTINGS_MODULE", "vlamy_ocr.settings_no_auth")\n\ | |
| execute_from_command_line(["manage.py", "migrate", "--noinput"])\n\ | |
| self._migrations_applied = True\n\ | |
| print("Migrations applied successfully")\n\ | |
| \n\ | |
| # Create anonymous user\n\ | |
| if not self._anonymous_user:\n\ | |
| self._anonymous_user, created = User.objects.get_or_create(\n\ | |
| username="anonymous",\n\ | |
| defaults={\n\ | |
| "email": "[email protected]",\n\ | |
| "first_name": "Anonymous",\n\ | |
| "last_name": "User"\n\ | |
| }\n\ | |
| )\n\ | |
| \n\ | |
| # Ensure user profile exists and is approved\n\ | |
| if hasattr(self._anonymous_user, "profile"):\n\ | |
| if not self._anonymous_user.profile.is_approved:\n\ | |
| self._anonymous_user.profile.is_approved = True\n\ | |
| self._anonymous_user.profile.save()\n\ | |
| else:\n\ | |
| from ocr_app.models import UserProfile\n\ | |
| profile, profile_created = UserProfile.objects.get_or_create(\n\ | |
| user=self._anonymous_user,\n\ | |
| defaults={"is_approved": True}\n\ | |
| )\n\ | |
| \n\ | |
| print(f"Anonymous user ready: created={created}, user_id={self._anonymous_user.id}")\n\ | |
| \n\ | |
| self._setup_complete = True\n\ | |
| \n\ | |
| except Exception as e:\n\ | |
| print(f"Error in middleware setup: {e}")\n\ | |
| # Fallback to Django AnonymousUser\n\ | |
| self._anonymous_user = AnonymousUser()\n\ | |
| \n\ | |
| def __call__(self, request):\n\ | |
| # Ensure setup is complete\n\ | |
| self._ensure_migrations_and_user()\n\ | |
| \n\ | |
| # Always assign the anonymous user to the request\n\ | |
| request.user = self._anonymous_user\n\ | |
| \n\ | |
| response = self.get_response(request)\n\ | |
| return response\n\ | |
| ' > /app/vlamy_ocr/middleware.py | |
| # Create a startup script for no-auth mode | |
| RUN echo '#!/bin/bash\n\ | |
| \n\ | |
| # Set the custom settings module\n\ | |
| export DJANGO_SETTINGS_MODULE=vlamy_ocr.settings_no_auth\n\ | |
| \n\ | |
| echo "Starting VLAMy in browser-only mode (no authentication required)"\n\ | |
| echo "Anonymous user will be created automatically on first request"\n\ | |
| \n\ | |
| # Start the Django development server (migrations will run automatically)\n\ | |
| python manage.py runserver 0.0.0.0:$PORT\n\ | |
| ' > /app/start.sh | |
| # Set proper permissions for all files and ensure startup script is executable | |
| RUN chmod -R 755 /app && \ | |
| chmod +x /app/start.sh && \ | |
| chown -R root:root /app | |
| # Environment variables for production (no-auth mode) | |
| ENV DEBUG=True | |
| ENV SECRET_KEY="browser-only-key-no-sensitive-data" | |
| ENV ALLOWED_HOSTS="*" | |
| ENV DJANGO_SETTINGS_MODULE="vlamy_ocr.settings_no_auth" | |
| # Expose port | |
| EXPOSE 7860 | |
| # Start the application | |
| CMD ["/app/start.sh"] |