From 1a51e6bc3946ca2405b6118a8b36136ca890508f Mon Sep 17 00:00:00 2001 From: Desktop Date: Wed, 12 Nov 2025 10:46:01 +0500 Subject: [PATCH] image url --- backend/igny8_core/ai/tasks.py | 60 ++-------- backend/igny8_core/modules/writer/views.py | 37 +----- docker-compose.yml | 129 +++++++++++++++++++++ 3 files changed, 142 insertions(+), 84 deletions(-) create mode 100644 docker-compose.yml diff --git a/backend/igny8_core/ai/tasks.py b/backend/igny8_core/ai/tasks.py index b743513a..f34a11da 100644 --- a/backend/igny8_core/ai/tasks.py +++ b/backend/igny8_core/ai/tasks.py @@ -527,67 +527,23 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None } ) - # Download and save image to /data/app/images + # Download and save image to /data/app/igny8/frontend/public/images/ai-images saved_file_path = None if image_url: try: import os import requests - from django.conf import settings - from pathlib import Path + import time - # Create images directory if it doesn't exist - # Use frontend/public/images/ai-images/ for web accessibility (like /images/logo/) - # This allows images to be served via app.igny8.com/images/ai-images/ - write_test_passed = False - images_dir = None + # Use the correct path: /data/app/igny8/frontend/public/images/ai-images + # This is web-accessible via /images/ai-images/ (Vite serves from public/) + images_dir = '/data/app/igny8/frontend/public/images/ai-images' - # Try frontend/public/images/ai-images/ first (web-accessible) - try: - # Use absolute path: /data/app/igny8/frontend/public/images/ai-images/ - # This matches the structure where frontend is at project root level - images_dir = '/data/app/igny8/frontend/public/images/ai-images' - os.makedirs(images_dir, exist_ok=True) - # Test write access - test_file = os.path.join(images_dir, '.write_test') - with open(test_file, 'w') as f: - f.write('test') - os.remove(test_file) - write_test_passed = True - logger.info(f"[process_image_generation_queue] Image {image_id} - Directory writable (web-accessible): {images_dir}") - except Exception as web_dir_error: - logger.warning(f"[process_image_generation_queue] Image {image_id} - Web-accessible directory not writable: {images_dir}, error: {web_dir_error}") - # Fallback to /data/app/igny8/images (mounted volume) - try: - images_dir = '/data/app/igny8/images' - os.makedirs(images_dir, exist_ok=True) - test_file = os.path.join(images_dir, '.write_test') - with open(test_file, 'w') as f: - f.write('test') - os.remove(test_file) - write_test_passed = True - logger.info(f"[process_image_generation_queue] Image {image_id} - Using mounted volume directory: {images_dir}") - except Exception as mounted_error: - logger.warning(f"[process_image_generation_queue] Image {image_id} - Mounted directory not writable: {images_dir}, error: {mounted_error}") - # Final fallback to /data/app/images - try: - images_dir = '/data/app/images' - os.makedirs(images_dir, exist_ok=True) - test_file = os.path.join(images_dir, '.write_test') - with open(test_file, 'w') as f: - f.write('test') - os.remove(test_file) - write_test_passed = True - logger.info(f"[process_image_generation_queue] Image {image_id} - Using fallback directory: {images_dir}") - except Exception as final_error: - logger.error(f"[process_image_generation_queue] Image {image_id} - All directories not writable. Last error: {final_error}") - raise Exception(f"None of the image directories are writable. Last error: {final_error}") - - if not write_test_passed: - raise Exception(f"Failed to find writable directory for saving images") + # Create directory if it doesn't exist + os.makedirs(images_dir, exist_ok=True) + logger.info(f"[process_image_generation_queue] Image {image_id} - Using directory: {images_dir}") # Generate filename: image_{image_id}_{timestamp}.png (or .webp for Runware) - import time timestamp = int(time.time()) # Use webp extension if provider is Runware, otherwise png file_ext = 'webp' if provider == 'runware' else 'png' diff --git a/backend/igny8_core/modules/writer/views.py b/backend/igny8_core/modules/writer/views.py index 66358e7d..19d963f1 100644 --- a/backend/igny8_core/modules/writer/views.py +++ b/backend/igny8_core/modules/writer/views.py @@ -395,39 +395,12 @@ class ImagesViewSet(SiteSectorModelViewSet): file_path = image.image_path - # Verify file exists - if not, try alternative locations + # Verify file exists at the saved path if not os.path.exists(file_path): - logger.warning(f"[serve_image_file] Image {pk} - File not found at saved path: {file_path}, trying alternative locations...") - - # Try alternative locations based on the filename - filename = os.path.basename(file_path) - alternative_paths = [ - '/data/app/igny8/frontend/public/images/ai-images/' + filename, # Primary location (web-accessible) - '/data/app/igny8/images/' + filename, # Secondary location - '/data/app/images/' + filename, # Fallback location - ] - - # Try each alternative path - found = False - for alt_path in alternative_paths: - if os.path.exists(alt_path): - file_path = alt_path - logger.info(f"[serve_image_file] Image {pk} - Found file at alternative location: {file_path}") - # Update database with correct path - try: - image.image_path = file_path - image.save(update_fields=['image_path']) - logger.info(f"[serve_image_file] Image {pk} - Updated database with correct path: {file_path}") - except Exception as update_error: - logger.warning(f"[serve_image_file] Image {pk} - Failed to update database path: {update_error}") - found = True - break - - if not found: - logger.error(f"[serve_image_file] Image {pk} - File not found in any location. Tried: {[file_path] + alternative_paths}") - return Response({ - 'error': f'Image file not found at: {file_path} (also checked alternative locations)' - }, status=status.HTTP_404_NOT_FOUND) + logger.error(f"[serve_image_file] Image {pk} - File not found at saved path: {file_path}") + return Response({ + 'error': f'Image file not found at: {file_path}' + }, status=status.HTTP_404_NOT_FOUND) # Check if file is readable if not os.access(file_path, os.R_OK): diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..d90ee802 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,129 @@ +version: "3.9" + +# ============================================================================= +# MASTER DOCKER COMPOSE - SINGLE SOURCE OF TRUTH +# ============================================================================= +# This file manages ALL apps and shared services +# Used by both Portainer and CLI - no conflicts +# ============================================================================= + +services: + # =========================================================================== + # SHARED SERVICES (Global - used by all apps) + # =========================================================================== + + postgres: + image: postgres:15 + container_name: igny8_postgres + restart: always + environment: + POSTGRES_USER: igny8 + POSTGRES_PASSWORD: igny8pass + POSTGRES_DB: igny8_db + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} || exit 1"] + interval: 20s + timeout: 5s + retries: 5 + start_period: 15s + networks: [igny8_net] + + redis: + image: redis:7 + container_name: igny8_redis + restart: always + command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] + volumes: + - redisdata:/data + healthcheck: + test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"] + interval: 20s + timeout: 3s + retries: 5 + networks: [igny8_net] + + pgadmin: + image: dpage/pgadmin4 + container_name: igny8_pgadmin + restart: always + environment: + PGADMIN_DEFAULT_EMAIL: admin@igny8.com + PGADMIN_DEFAULT_PASSWORD: admin123 + ports: + - "0.0.0.0:5050:80" + volumes: + - pgadmin_data:/var/lib/pgadmin + networks: [igny8_net] + + filebrowser: + image: filebrowser/filebrowser:v2.25.0 + container_name: igny8_filebrowser + restart: always + environment: + TZ: Asia/Karachi + ports: + - "0.0.0.0:8080:80" + volumes: + - /data:/srv + - /backups:/srv/backups + - filebrowser_db:/database + networks: [igny8_net] + labels: + - "com.docker.compose.project=igny8-infra" + - "com.docker.compose.service=filebrowser" + + gitea: + image: gitea/gitea:latest + container_name: gitea + restart: always + environment: + - USER_UID=1000 + - USER_GID=1000 + volumes: + - ./gitea:/data + - /data/app/igny8:/deploy/igny8:rw # Mount app directory for deployment + ports: + - "0.0.0.0:3000:3000" # Web UI + - "0.0.0.0:2222:22" # SSH for Git access + networks: [igny8_net] + labels: + - "com.docker.compose.project=igny8-infra" + - "com.docker.compose.service=gitea" + + caddy: + image: caddy:latest + container_name: igny8_caddy + restart: always + ports: + - "80:80" + - "443:443" + volumes: + - caddy_data:/data + - caddy_config:/config + # Mount Caddyfile for routing configuration + - /var/lib/docker/volumes/portainer_data/_data/caddy/Caddyfile:/etc/caddy/Caddyfile + networks: [igny8_net] + + setup-helper: + image: alpine:3.20 + container_name: setup-helper + command: ["sh", "-c", "sleep infinity"] + restart: always + networks: [igny8_net] + volumes: + - /data/backups:/backups:rw + - /scripts:/scripts:ro + +volumes: + pgdata: + redisdata: + pgadmin_data: + filebrowser_db: + caddy_data: + caddy_config: + +networks: + igny8_net: + external: true