SciSkin / app.py
Ziyi98's picture
Upload 9 files
08d5f5f verified
from flask import Flask, render_template, request, jsonify
from werkzeug.utils import secure_filename
import os, json, time
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
UPLOAD_DIR = os.path.join(APP_ROOT, 'uploads')
os.makedirs(UPLOAD_DIR, exist_ok=True)
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 25 * 1024 * 1024 # 25MB
# === Load system prompt ===
prompt_path = os.path.join(APP_ROOT, 'prompts', 'skin_prompt.txt')
if os.path.exists(prompt_path):
with open(prompt_path, 'r', encoding='utf-8') as f:
SYSTEM_PROMPT = f.read()
else:
SYSTEM_PROMPT = "MISSING_PROMPT: please add prompts/skin_prompt.txt"
# === (Optional) Load JSON schema for basic shape validation ===
schema_path = os.path.join(APP_ROOT, 'schema', 'output_schema.json')
if os.path.exists(schema_path):
with open(schema_path, 'r', encoding='utf-8') as f:
OUTPUT_SCHEMA = json.load(f)
else:
OUTPUT_SCHEMA = {}
def _stub_model_inference(image_paths, metadata: dict):
"""
Deterministic stub to simulate the model output that conforms to the schema.
Replace this with your real model call (e.g., OpenAI, local vision model, etc.).
"""
num_images = len(image_paths)
quality = 'good' if num_images and metadata.get('lighting', 'even') == 'even' else 'fair'
result = {
"image_quality": {
"overall": quality,
"issues": [] if quality == 'good' else ["lighting"],
"retake_advice": "确保均匀光线、正面构图、去除滤镜与妆容。"
},
"global_assessment": {
"skin_type_estimate": metadata.get('self_report_skin_type', 'unknown'),
"overall_risk_score": 42,
"notes": "演示结果:请接入真实模型以获得更准确评估。"
},
"region_scores": {
"T_zone_oiliness": 58,
"U_zone_dryness": 25,
"cheek_redness": 18,
"undereye_dark_circle": 40
},
"concerns": [
{"name": "acne", "severity": 35, "evidence": "T区可见散在闭口样阴影。", "confidence": 0.72},
{"name": "pores", "severity": 55, "evidence": "鼻翼与鼻梁两侧纹理增粗。", "confidence": 0.77}
],
"pigmentation": {
"uneven_tone": 28,
"spots": 10,
"melasma_like": 0,
"sun_damage_like": 22
},
"aging_signs": {
"fine_lines": 20,
"wrinkles": 8,
"loss_of_elasticity": 12,
"texture_roughness": 30
},
"sensitivity_inflammation": {
"redness": 18,
"visible_capillaries": 5,
"irritation": 10
},
"top_priorities": [
{"name": "pores", "reason": "毛孔纹理明显,影响观感。"},
{"name": "oil_control", "reason": "T区油脂分泌偏旺。"},
{"name": "uneven_tone", "reason": "肤色轻度不匀影响通透感。"}
],
"daily_plan": {
"am": [
"氨基酸洁面",
"2-5%烟酰胺精华(避眼周)",
"广谱防晒 SPF50+ PA++++"
],
"pm": [
"温和洁面",
"0.5-2%水杨酸/杜鹃花酸按需点涂",
"清爽型保湿乳"
],
"extras_weekly": [
"每周1-2次温和去角质(避免与酸叠加)"
]
},
"ingredient_recommendations": [
{
"goal": "oil_control",
"actives": ["niacinamide 2-5%", "salicylic acid 0.5-2%"],
"usage": "先低后高,观察耐受,白天注意防晒。",
"cautions": "与强酸类/维A初期分开使用,避免刺激叠加。"
}
],
"risk_flags": [],
"follow_up": {
"reshoot_tips": ["remove_makeup", "even_lighting", "front_facing", "no_filters"],
"retake_interval_days": 28
}
}
return result
@app.route('/')
def index():
return render_template('index.html')
@app.post('/api/analyze')
def analyze():
files = request.files.getlist('images')
metadata_json = request.form.get('metadata', '{}')
try:
metadata = json.loads(metadata_json)
except Exception:
return jsonify({"error": "metadata must be valid JSON"}), 400
saved = []
ts = int(time.time())
for f in files[:5]: # cap 5 images
if not f.filename:
continue
fname = f"{ts}_" + secure_filename(f.filename)
path = os.path.join(UPLOAD_DIR, fname)
f.save(path)
saved.append(path)
# Call your model (stubbed here)
output = _stub_model_inference(saved, metadata)
# Minimal shape check
required_top_keys = [
"image_quality", "global_assessment", "region_scores", "concerns",
"pigmentation", "aging_signs", "sensitivity_inflammation",
"top_priorities", "daily_plan", "ingredient_recommendations",
"risk_flags", "follow_up"
]
missing = [k for k in required_top_keys if k not in output]
if missing:
return jsonify({"error": f"missing keys: {missing}"}), 500
return jsonify(output)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)