Organized the application into separate frontend and backend directories for cleaner deployment and better separation of concerns. Frontend Directory (frontend/): - index.html: Single-page web interface (renamed from web_ui.html) - README.md: Frontend deployment guide - Total size: ~113 KB (self-contained) - Smart base path detection (works at / or /ai_qc/) - No configuration changes required Backend Directory (backend/): - All Python files (api_server.py, llm_config.py, etc.) - visual_qc_apps/: 33 QC check modules - profiles/: 6 QC profile configurations - brand_guidelines/: Reference asset storage - config/: Environment configurations - scripts/: Deployment automation - uploads/, output/: Data directories - requirements.txt, ai_qc.service, apache_config.conf - Complete documentation New Documentation: - FOLDER_STRUCTURE.md: Comprehensive guide to new structure - frontend/README.md: Frontend deployment instructions - backend/BACKEND_README.md: Backend deployment guide Deployment Mapping: - frontend/ → /var/www/html/ai_qc/ (web root) - backend/ → /opt/ai_qc/ (application directory) Benefits: - Clear separation of concerns - Backend code not in web-accessible directory - Independent frontend/backend updates - Matches server's existing patterns (/opt/veo3, /opt/voice2text) - Industry-standard architecture - Easy to deploy and maintain Original files preserved in root directory for reference. Ready for production deployment following MIGRATION_GUIDE.md. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
55 lines
No EOL
2.2 KiB
Python
Executable file
55 lines
No EOL
2.2 KiB
Python
Executable file
import os
|
|
import base64
|
|
import io
|
|
import time
|
|
from PIL import Image
|
|
import fitz # PyMuPDF
|
|
import cv2 # OpenCV for video frames
|
|
|
|
# Import from centralized LLM configuration
|
|
from llm_config import run_visual_qc, pil_image_to_base64, get_model_info
|
|
|
|
# --- Helper Functions ---
|
|
def get_image_from_asset(asset_path, target_size=(1024, 1024)):
|
|
"""
|
|
Loads an image from various asset types (image, pdf, video).
|
|
Extracts the first page/frame and returns a PIL Image object.
|
|
Resizes the image if it's larger than target_size while maintaining aspect ratio.
|
|
"""
|
|
try:
|
|
file_extension = os.path.splitext(asset_path)[1].lower()
|
|
pil_image = None
|
|
|
|
if file_extension in ['.png', '.jpg', '.jpeg', '.bmp', '.webp', '.gif', '.tiff']:
|
|
pil_image = Image.open(asset_path).convert('RGB')
|
|
elif file_extension == '.pdf':
|
|
doc = fitz.open(asset_path)
|
|
if doc.page_count > 0:
|
|
page = doc.load_page(0) # Load the first page
|
|
# Render page to a pixmap at a reasonable DPI
|
|
zoom = 2.0 # Increase DPI for better quality (150 DPI)
|
|
mat = fitz.Matrix(zoom, zoom)
|
|
pix = page.get_pixmap(matrix=mat, alpha=False) # alpha=False for RGB
|
|
pil_image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
|
|
doc.close()
|
|
elif file_extension in ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv']:
|
|
cap = cv2.VideoCapture(asset_path)
|
|
if cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if ret:
|
|
# Convert OpenCV frame (BGR) to PIL Image (RGB)
|
|
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
pil_image = Image.fromarray(frame_rgb)
|
|
cap.release()
|
|
|
|
if pil_image:
|
|
# Resize image if it's too large for the API, maintaining aspect ratio
|
|
pil_image.thumbnail(target_size, Image.Resampling.LANCZOS)
|
|
return pil_image
|
|
else:
|
|
print(f"Unsupported file type or error loading: {asset_path}")
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"Error processing asset {asset_path}: {e}")
|
|
return None |