This commit is contained in:
2025-09-25 20:25:18 -04:00
commit 80b6f3b902
25 changed files with 1749 additions and 0 deletions

146
main.py Normal file
View 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()