import os import time from flask import Flask, render_template, request, jsonify, send_from_directory from werkzeug.utils import secure_filename # Import Services (We will create these next) # Note: Ensure empty __init__.py exists in services/ folder from services.studio import StudioService from services.vision import VisionService from services.ai_studio import AIStudioService from services.utilities import UtilitiesService # Initialize Flask App app = Flask(__name__) # --- Configuration --- UPLOAD_FOLDER = 'static/uploads' ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'webp', 'bmp'} app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['MAX_CONTENT_LENGTH'] = 32 * 1024 * 1024 app.secret_key = 'radiant_secret_key_dev' # Ensure upload directory exists os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # Initialize Service Instances studio_service = StudioService() vision_service = VisionService() ai_service = AIStudioService() utilities_service = UtilitiesService() # --- Helpers --- def allowed_file(filename): return ( '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS ) def get_file_path(filename): return os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(filename)) def generate_output_filename(original_filename, prefix="processed"): timestamp = int(time.time()) name, ext = os.path.splitext(original_filename) return f"{prefix}_{timestamp}_{name}{ext}" # --- Page Routes (Frontend) --- @app.route('/') def index(): return render_template('onboarding.html') @app.route('/studio') def studio(): return render_template('studio.html') @app.route('/vision') def vision(): return render_template('vision.html') @app.route('/ai-studio') def ai_studio(): return render_template('ai_studio.html') @app.route('/utilities') def utilities(): return render_template('utilities.html') @app.route('/about') def about(): return render_template('about.html') #@app.route('/products') #def products(): # return render_template('products.html') @app.route('/docs') def docs(): return render_template('docs.html') @app.route('/download') def download(): return render_template('download.html') # --- API: Core Upload --- @app.route('/api/upload', methods=['POST']) def upload_file(): if 'file' not in request.files: return jsonify({'success': False, 'error': 'No file part'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'success': False, 'error': 'No selected file'}), 400 if file and allowed_file(file.filename): # Create unique filename filename = secure_filename(f"{int(time.time())}_{file.filename}") filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) return jsonify({ 'success': True, 'filename': filename, 'url': f"/static/uploads/{filename}" }) return jsonify({'success': False, 'error': 'Invalid file type'}), 400 # --- API: Studio (Image Editing) --- @app.route('/api/process-studio', methods=['POST']) def process_studio(): try: data = request.json filename = data.get('filename') options = data.get('options') # Contains brightness, contrast, filter, etc. if not filename or not options: return jsonify({'success': False, 'error': 'Missing parameters'}), 400 input_path = get_file_path(filename) output_filename = generate_output_filename(filename, "edit") output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename) # Call Service success, result = studio_service.process_request(input_path, output_path, options) if success: return jsonify({ 'success': True, 'url': f"/static/uploads/{output_filename}", 'filename': output_filename }) else: return jsonify({'success': False, 'error': str(result)}), 500 except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # --- API: Vision (YOLO, BG Remove) --- @app.route('/api/process-vision', methods=['POST']) def process_vision(): try: data = request.json filename = data.get('filename') task = data.get('task') # extra options like 'color' for bg replacement or 'value' for blur intensity options = data if not filename or not task: return jsonify({'success': False, 'error': 'Missing parameters'}), 400 input_path = get_file_path(filename) output_filename = generate_output_filename(filename, f"vision_{task}") output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename) success, result_meta = vision_service.process_request(input_path, output_path, task, options) if success: response = { 'success': True, 'url': f"/static/uploads/{output_filename}", 'filename': output_filename } # Add detections if they exist (for YOLO) if isinstance(result_meta, dict) and 'detections' in result_meta: response['detections'] = result_meta['detections'] return jsonify(response) else: return jsonify({'success': False, 'error': str(result_meta)}), 500 except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # --- API: AI Studio (Colorize, Upscale) --- @app.route('/api/process-ai', methods=['POST']) def process_ai(): try: data = request.json filename = data.get('filename') task = data.get('task') if not filename or not task: return jsonify({'success': False, 'error': 'Missing parameters'}), 400 input_path = get_file_path(filename) output_filename = generate_output_filename(filename, f"ai_{task}") output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename) success, result = ai_service.process_request(input_path, output_path, task) if success: return jsonify({ 'success': True, 'url': f"/static/uploads/{output_filename}", 'filename': output_filename }) else: return jsonify({'success': False, 'error': str(result)}), 500 except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # --- API: Utilities (Convert, Resize) --- @app.route('/api/process-utility', methods=['POST']) def process_utility(): try: data = request.json filename = data.get('filename') # Service handles specific logic internally input_path = get_file_path(filename) # Output directory is passed so service can generate name based on format output_dir = app.config['UPLOAD_FOLDER'] success, result = utilities_service.process_request(input_path, output_dir, data) if success: if data.get('action') == 'metadata': return jsonify({'success': True, 'metadata': result}) else: return jsonify({ 'success': True, 'url': f"/static/uploads/{result}", 'filename': result }) else: return jsonify({'success': False, 'error': str(result)}), 500 except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # --- Serve Static Files (Images) --- @app.route('/static/uploads/') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) if __name__ == '__main__': #print("Radiant AI Server (local dev)") app.run(host='0.0.0.0', port=7860)