Initial
This commit is contained in:
146
main.py
Normal file
146
main.py
Normal file
@@ -0,0 +1,146 @@
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
from flask import Flask, jsonify, request, send_from_directory, render_template
|
||||
from flask_cors import CORS
|
||||
from PIL import Image
|
||||
from pillow_heif import register_heif_opener
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from images import PetPicture
|
||||
|
||||
app = Flask(__name__, static_folder="ppq-frontend/dist/static", template_folder="ppq-frontend/dist")
|
||||
app.config['UPLOAD_FOLDER'] = 'uploads'
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||
|
||||
CORS(app)
|
||||
|
||||
register_heif_opener()
|
||||
|
||||
|
||||
def allowed_file(filename):
|
||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp', 'heic'}
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
def allowed_file(filename):
|
||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp', 'heic', 'heif'}
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
def is_heic_file(filename, mimetype):
|
||||
"""Check if file is HEIC/HEIF"""
|
||||
extension = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
|
||||
return extension in ['heic', 'heif'] or mimetype in ['image/heic', 'image/heif']
|
||||
|
||||
def convert_heic_image(file_stream, output_path, quality=85):
|
||||
"""Convert HEIC image from file stream"""
|
||||
try:
|
||||
# Open image from stream
|
||||
image = Image.open(file_stream)
|
||||
|
||||
# Convert to RGB if needed (HEIC can have different color modes)
|
||||
if image.mode not in ['RGB', 'L']:
|
||||
image = image.convert('RGB')
|
||||
|
||||
# Save as JPEG
|
||||
image.save(output_path, 'JPEG', quality=quality, optimize=True)
|
||||
return True, None
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
# Serve React static files
|
||||
@app.route('/static/<path:filename>')
|
||||
def static_files(filename):
|
||||
return send_from_directory(app.static_folder, filename)
|
||||
|
||||
# Serve the React app for all routes (catch-all)
|
||||
@app.route('/', defaults={'path': ''})
|
||||
@app.route('/<path:path>')
|
||||
def serve_react_app(path):
|
||||
if path and os.path.exists(os.path.join(app.template_folder, path)):
|
||||
return send_from_directory(app.template_folder, path)
|
||||
return render_template('index.html')
|
||||
|
||||
# List pictures
|
||||
# Create a picture entry
|
||||
# Edit a picture metadata
|
||||
@app.route("/api/pictures", methods=["GET", "POST", "PATCH"])
|
||||
def list_pictures():
|
||||
if request.method == "GET":
|
||||
return jsonify([pp.get_json() for pp in PetPicture.get_all()])
|
||||
elif request.method == "POST":
|
||||
title = request.form.get("title")
|
||||
contributor = request.form.get("contributor")
|
||||
description = request.form.get("description")
|
||||
image = request.files.get("image")
|
||||
timestamp = int(datetime.now().timestamp())
|
||||
|
||||
# Validate
|
||||
if image is None:
|
||||
return jsonify({"error": "No file provided"}), 400
|
||||
|
||||
if image and allowed_file(image.filename):
|
||||
# Check if it's HEIC
|
||||
if is_heic_file(image.filename, image.mimetype):
|
||||
# Convert HEIC to JPEG
|
||||
original_name = image.filename.rsplit('.', 1)[0]
|
||||
filename = f"{timestamp}_{original_name}.jpg"
|
||||
output_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
|
||||
# Reset file stream position
|
||||
image.stream.seek(0)
|
||||
|
||||
success, error_msg = convert_heic_image(image.stream, output_path)
|
||||
|
||||
if not success:
|
||||
return jsonify({'error': f'HEIC conversion failed: {error_msg}'}), 500
|
||||
|
||||
else:
|
||||
# Secure the filename
|
||||
filename = secure_filename(image.filename)
|
||||
|
||||
# Save the file
|
||||
image.save(os.path.join('uploads', filename))
|
||||
|
||||
pic = PetPicture(title=title,
|
||||
contributor=contributor,
|
||||
created_at=timestamp,
|
||||
filepath=filename,
|
||||
description=description)
|
||||
pic.upsert()
|
||||
|
||||
return jsonify({'message': 'File uploaded successfully', 'filename': filename})
|
||||
|
||||
return jsonify({'error': 'Something went wrong'}), 400
|
||||
|
||||
|
||||
@app.route('/uploads/<filename>')
|
||||
def uploaded_file(filename):
|
||||
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
||||
|
||||
@app.route("/api/pictures/<string:uuid>", methods=["GET", "PATCH"])
|
||||
def single_picture(uuid):
|
||||
if request.method == "GET":
|
||||
pet_picture = PetPicture.get(uuid=uuid)
|
||||
return jsonify(pet_picture.get_json())
|
||||
elif request.method == "PATCH":
|
||||
data = request.get_json()
|
||||
print(data)
|
||||
pic = PetPicture(uuid=uuid,
|
||||
title=data.get("title"),
|
||||
contributor=data.get("contributor"),
|
||||
created_at=data.get("created_at"),
|
||||
filepath=data.get("filepath"),
|
||||
description=data.get("description"))
|
||||
pic.upsert()
|
||||
return jsonify(pic.get_json()), 200
|
||||
|
||||
|
||||
def main():
|
||||
print("Hello from ppq!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user