ai_qc/backend/visual_qc_apps/flask_app_template.py
nickviljoen 3fec052c12 Create frontend and backend folder structure for deployment
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>
2025-11-06 11:55:53 +02:00

133 lines
No EOL
5 KiB
Python
Executable file

from flask import Flask, request, jsonify
import os
import base64
import tempfile
from visual_qc_apps.utils import run_visual_qc
class FlaskAppTemplate:
"""Base template for Visual QC Flask applications"""
def __init__(self, name, prompt):
"""
Initialize the Flask app with a specific prompt
Args:
name (str): Name of the app
prompt (str): The hardcoded prompt to use
"""
self.app = Flask(name)
# Add scoring instructions to the prompt
scoring_instructions = """
SCORING INSTRUCTIONS:
After your analysis, provide a numerical score from 1 to 10 (with 10 being perfect/excellent and 1 being poor/inadequate) based on how well the asset meets the criteria.
YOUR OUTPUT FORMAT:
Include a JSON code block with the following fields:
- "score": a number from 1 to 10
- "explanation": your detailed reasoning for the score
- "recommendations": specific suggestions for improvement if applicable
Example:
```json
{
"score": 8,
"explanation": "The logo is clearly visible and occupies approximately 12% of the advertisement area, which exceeds the minimum requirement. It has good contrast against the background and would be recognizable from the appropriate viewing distance.",
"recommendations": "Consider increasing contrast around the edges of the logo for even better visibility in darker environments."
}
```
"""
# Combine the base prompt with scoring instructions
self.prompt = prompt + scoring_instructions
# Register routes
self.register_routes()
def register_routes(self):
"""Register all API routes"""
@self.app.route('/')
def index():
return jsonify({
"status": "ok",
"message": "Visual QC API active",
"endpoints": [
"/api/analyze (POST)",
"/api/health (GET)"
]
})
@self.app.route('/api/health', methods=['GET'])
def health_check():
return jsonify({"status": "healthy"})
@self.app.route('/api/analyze', methods=['POST'])
def analyze_image():
# Check if request has the required data
if not request.json:
return jsonify({"status": "error", "message": "Request must be JSON"}), 400
# Validate required fields
if 'image' not in request.json:
return jsonify({"status": "error", "message": "Missing 'image' field"}), 400
# Get parameters
image_base64 = request.json.get('image') # Required
reference_base64 = request.json.get('reference') # Optional
model = request.json.get('model', 'Gemini') # Optional, default to Gemini
# Validate model selection
if model not in ["Gemini", "OpenAI"]:
return jsonify({"status": "error", "message": "Invalid model. Choose 'Gemini' or 'OpenAI'"}), 400
try:
# Create temporary files for images
with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as main_file:
main_file.write(base64.b64decode(image_base64))
main_path = main_file.name
ref_path = None
if reference_base64:
with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as ref_file:
ref_file.write(base64.b64decode(reference_base64))
ref_path = ref_file.name
# Process the QC request
result = run_visual_qc(
prompt=self.prompt,
asset_path=main_path,
reference_path=ref_path,
model_name=model
)
# Clean up temp files
try:
os.unlink(main_path)
if ref_path:
os.unlink(ref_path)
except Exception as e:
print(f"Error cleaning up temp files: {e}")
# Return the result
if result["status"] == "success":
return jsonify({
"status": "success",
"model": model,
"response": result["response"]
})
else:
return jsonify({
"status": "error",
"message": result["message"]
}), 500
except Exception as e:
return jsonify({
"status": "error",
"message": f"Server error: {str(e)}"
}), 500
def run(self, host='0.0.0.0', port=5001, debug=False):
"""Run the Flask application"""
self.app.run(host=host, port=port, debug=debug)