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)