Preftified the webpage
This commit is contained in:
parent
50c556e8b0
commit
e926625878
3 changed files with 140 additions and 79 deletions
42
main.py
42
main.py
|
|
@ -1,14 +1,17 @@
|
|||
# main.py
|
||||
import os
|
||||
from flask import Flask, request, render_template
|
||||
from timelapse import process_faces
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Read critical parameters from environment variables
|
||||
DEFAULT_API_KEY = os.environ.get("IMMICH_API_KEY", "")
|
||||
DEFAULT_BASE_URL = os.environ.get("IMMICH_BASE_URL", "")
|
||||
DEFAULT_OUTPUT_FOLDER = os.environ.get("IMMICH_OUTPUT_FOLDER", "output")
|
||||
# Critical parameters provided via environment variables
|
||||
API_KEY = os.environ.get("IMMICH_API_KEY", "")
|
||||
BASE_URL = os.environ.get("IMMICH_BASE_URL", "")
|
||||
OUTPUT_FOLDER = os.environ.get("OUTPUT_FOLDER", "output")
|
||||
|
||||
# model paths
|
||||
FACE_DETECT_MODEL = "mmod_human_face_detector.dat"
|
||||
LANDMARK_MODEL = "shape_predictor_68_face_landmarks.dat"
|
||||
|
||||
|
||||
@app.route("/", methods=["GET", "POST"])
|
||||
|
|
@ -17,24 +20,17 @@ def index():
|
|||
error = None
|
||||
if request.method == "POST":
|
||||
try:
|
||||
# Use environment variable defaults if form fields are empty
|
||||
api_key = request.form.get("api_key") or DEFAULT_API_KEY
|
||||
base_url = request.form.get("base_url") or DEFAULT_BASE_URL
|
||||
output_folder = request.form.get("output_folder") or DEFAULT_OUTPUT_FOLDER
|
||||
api_key = API_KEY
|
||||
base_url = BASE_URL
|
||||
output_folder = OUTPUT_FOLDER
|
||||
person_id = request.form["person_id"]
|
||||
|
||||
# Convert numeric parameters with defaults if conversion fails
|
||||
padding_percent = float(request.form.get("padding_percent", 0.3))
|
||||
resize_width = int(request.form.get("resize_width", 512))
|
||||
resize_height = int(request.form.get("resize_height", 512))
|
||||
min_face_width = int(request.form.get("min_face_width", 128))
|
||||
min_face_height = int(request.form.get("min_face_height", 128))
|
||||
resize_size = int(request.form.get("resize_size", 512))
|
||||
face_resolution_threshold = int(request.form.get("face_resolution_threshold", 128))
|
||||
pose_threshold = float(request.form.get("pose_threshold", 25))
|
||||
desired_left_eye_x = float(request.form.get("desired_left_eye_x", 0.35))
|
||||
desired_left_eye_y = float(request.form.get("desired_left_eye_y", 0.45))
|
||||
max_workers = int(request.form.get("max_workers", 4))
|
||||
face_detect_model_path = request.form.get("face_detect_model_path", "mmod_human_face_detector.dat")
|
||||
landmark_model_path = request.form.get("landmark_model_path", "shape_predictor_68_face_landmarks.dat")
|
||||
|
||||
processed_files = process_faces(
|
||||
api_key=api_key,
|
||||
|
|
@ -42,15 +38,15 @@ def index():
|
|||
person_id=person_id,
|
||||
output_folder=output_folder,
|
||||
padding_percent=padding_percent,
|
||||
resize_width=resize_width,
|
||||
resize_height=resize_height,
|
||||
min_face_width=min_face_width,
|
||||
min_face_height=min_face_height,
|
||||
resize_width=resize_size,
|
||||
resize_height=resize_size,
|
||||
min_face_width=face_resolution_threshold,
|
||||
min_face_height=face_resolution_threshold,
|
||||
pose_threshold=pose_threshold,
|
||||
desired_left_eye=(desired_left_eye_x, desired_left_eye_y),
|
||||
max_workers=max_workers,
|
||||
face_detect_model_path=face_detect_model_path,
|
||||
landmark_model_path=landmark_model_path
|
||||
face_detect_model_path=FACE_DETECT_MODEL,
|
||||
landmark_model_path=LANDMARK_MODEL
|
||||
)
|
||||
result = f"Finished processing. {len(processed_files)} images saved in '{output_folder}'."
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1,61 +1,128 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Immich Selfie Timelapse Tool</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f5f5f5;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 50px auto;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
padding: 30px;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
color: #555;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
width: calc(100% - 20px);
|
||||
padding: 8px 10px;
|
||||
margin-top: 4px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
details {
|
||||
background: #eef;
|
||||
padding: 10px;
|
||||
margin: 20px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
summary {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
background: #28a745;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 20px auto 0;
|
||||
}
|
||||
button:hover {
|
||||
background: #218838;
|
||||
}
|
||||
.result, .error {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.error {
|
||||
color: #c00;
|
||||
}
|
||||
.result {
|
||||
color: #080;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Create a Selfie Timelapse</h1>
|
||||
{% if error %}
|
||||
<p style="color:red;">{{ error }}</p>
|
||||
{% endif %}
|
||||
<form method="post">
|
||||
<label>API Key:
|
||||
<input type="text" name="api_key" value="{{ request.form.api_key or config['IMMICH_API_KEY'] or '' }}">
|
||||
</label><br><br>
|
||||
<label>Base URL:
|
||||
<input type="text" name="base_url" value="{{ request.form.base_url or config['IMMICH_BASE_URL'] or '' }}">
|
||||
</label><br><br>
|
||||
<label>Output Folder:
|
||||
<input type="text" name="output_folder" value="{{ request.form.output_folder or config['IMMICH_OUTPUT_FOLDER'] or 'output' }}">
|
||||
</label><br><br>
|
||||
<label>Person ID: <input type="text" name="person_id" required></label><br><br>
|
||||
<label>Padding Percent:
|
||||
<input type="number" step="0.01" name="padding_percent" value="{{ request.form.padding_percent or 0.3 }}">
|
||||
</label><br><br>
|
||||
<label>Resize Width:
|
||||
<input type="number" name="resize_width" value="{{ request.form.resize_width or 512 }}">
|
||||
</label><br><br>
|
||||
<label>Resize Height:
|
||||
<input type="number" name="resize_height" value="{{ request.form.resize_height or 512 }}">
|
||||
</label><br><br>
|
||||
<label>Min Face Width:
|
||||
<input type="number" name="min_face_width" value="{{ request.form.min_face_width or 128 }}">
|
||||
</label><br><br>
|
||||
<label>Min Face Height:
|
||||
<input type="number" name="min_face_height" value="{{ request.form.min_face_height or 128 }}">
|
||||
</label><br><br>
|
||||
<label>Pose Threshold:
|
||||
<input type="number" step="0.1" name="pose_threshold" value="{{ request.form.pose_threshold or 25 }}">
|
||||
</label><br><br>
|
||||
<label>Desired Left Eye X:
|
||||
<input type="number" step="0.01" name="desired_left_eye_x" value="{{ request.form.desired_left_eye_x or 0.35 }}">
|
||||
</label><br><br>
|
||||
<label>Desired Left Eye Y:
|
||||
<input type="number" step="0.01" name="desired_left_eye_y" value="{{ request.form.desired_left_eye_y or 0.45 }}">
|
||||
</label><br><br>
|
||||
<label>Max Workers:
|
||||
<input type="number" name="max_workers" value="{{ request.form.max_workers or 4 }}">
|
||||
</label><br><br>
|
||||
<label>Face Detect Model Path:
|
||||
<input type="text" name="face_detect_model_path" value="{{ request.form.face_detect_model_path or 'mmod_human_face_detector.dat' }}">
|
||||
</label><br><br>
|
||||
<label>Landmark Model Path:
|
||||
<input type="text" name="landmark_model_path" value="{{ request.form.landmark_model_path or 'shape_predictor_68_face_landmarks.dat' }}">
|
||||
</label><br><br>
|
||||
<button type="submit">Generate Timelapse</button>
|
||||
</form>
|
||||
{% if result %}
|
||||
<h2>{{ result }}</h2>
|
||||
{% endif %}
|
||||
<div class="container">
|
||||
<h1>Immich Selfie Timelapse Tool</h1>
|
||||
{% if error %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endif %}
|
||||
<form method="post">
|
||||
<label>
|
||||
Person ID:
|
||||
<input type="text" name="person_id" required>
|
||||
</label>
|
||||
<label>
|
||||
Padding Percent:
|
||||
<input type="number" step="0.01" name="padding_percent" value="{{ request.form.padding_percent or 0.3 }}">
|
||||
</label>
|
||||
<label>
|
||||
Output Image Size:
|
||||
<input type="number" name="resize_size" value="{{ request.form.resize_size or 512 }}">
|
||||
</label>
|
||||
<label>
|
||||
Face Resolution Threshold:
|
||||
<input type="number" name="face_resolution_threshold" value="{{ request.form.face_resolution_threshold or 128 }}">
|
||||
</label>
|
||||
<label>
|
||||
Pose Threshold:
|
||||
<input type="number" step="0.1" name="pose_threshold" value="{{ request.form.pose_threshold or 25 }}">
|
||||
</label>
|
||||
<details>
|
||||
<summary>Advanced Options</summary>
|
||||
<label>
|
||||
Desired Left Eye X:
|
||||
<input type="number" step="0.01" name="desired_left_eye_x" value="{{ request.form.desired_left_eye_x or 0.35 }}">
|
||||
</label>
|
||||
<label>
|
||||
Desired Left Eye Y:
|
||||
<input type="number" step="0.01" name="desired_left_eye_y" value="{{ request.form.desired_left_eye_y or 0.45 }}">
|
||||
</label>
|
||||
<label>
|
||||
Max Workers:
|
||||
<input type="number" name="max_workers" value="{{ request.form.max_workers or 4 }}">
|
||||
</label>
|
||||
</details>
|
||||
<button type="submit">Generate Timelapse</button>
|
||||
</form>
|
||||
{% if result %}
|
||||
<p class="result">{{ result }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import os
|
|||
import io
|
||||
import requests
|
||||
import concurrent.futures
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
|
@ -243,7 +241,7 @@ def process_faces(
|
|||
min_face_height=128,
|
||||
pose_threshold=25,
|
||||
desired_left_eye=(0.35, 0.45),
|
||||
max_workers=4,
|
||||
max_workers=1,
|
||||
face_detect_model_path="mmod_human_face_detector.dat",
|
||||
landmark_model_path="shape_predictor_68_face_landmarks.dat"
|
||||
):
|
||||
|
|
|
|||
Loading…
Reference in a new issue