From 6ffc7f343d13044ce61f5549c98c5dffae21937b Mon Sep 17 00:00:00 2001 From: xsl Date: Thu, 6 Aug 2026 21:35:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=B7=E6=80=A7=E5=8F=91=E5=9E=8B?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E6=B3=A2=E6=B5=AA=E5=BD=A2(wave=3D7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接口2/5 male hair_style 增至 1..7,贴图 man_wave.png 纳入四套纹理目录,同步测试页与接口文档。 Co-authored-by: Cursor --- app.py | 18 +++++++++--------- docs/实现说明.md | 2 +- docs/接口文档.md | 10 +++++----- hairline/service.py | 5 +++-- hairline_texture/man_wave.png | Bin 0 -> 6487 bytes hairline_texture_black/man_wave.png | Bin 0 -> 4366 bytes hairline_texture_high/man_wave.png | Bin 0 -> 6517 bytes hairline_texture_low/man_wave.png | Bin 0 -> 6521 bytes static/test_interface2.html | 3 ++- static/test_interface5.html | 5 +++-- 10 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 hairline_texture/man_wave.png create mode 100644 hairline_texture_black/man_wave.png create mode 100644 hairline_texture_high/man_wave.png create mode 100644 hairline_texture_low/man_wave.png diff --git a/app.py b/app.py index 18da609..7b76d2b 100644 --- a/app.py +++ b/app.py @@ -1151,15 +1151,15 @@ async def face_measure_v2( --- -- **gender**(必填):`male` / `female`。决定返回的贴图集合(female 7 张 / male 6 张)。 +- **gender**(必填):`male` / `female`。决定返回的贴图集合(female 7 张 / male 7 张)。 非法或缺失返回 `1004`。 - **hair_style**(必填):发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数量。 `female`:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower; - `male`:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。越界/非法返回 `1007`。 + `male`:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal, 7=wave。越界/非法返回 `1007`。 - **beauty_enabled**:本期保留但不生效。 `hairline_type` 取值:`ellipse` / `flower` / `heart` / `straight` / `wave` / `bigflower` / `clasicalflower`(female), -`ellipse` / `m` / `straight` / `inverse_arc` / `heart` / `Softpetal`(male)。 +`ellipse` / `m` / `straight` / `inverse_arc` / `heart` / `Softpetal` / `wave`(male)。 """, responses={ 200: { @@ -1198,7 +1198,7 @@ async def hair_grow( image_url: Optional[str] = Form(default=None, description="图片 URL"), image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"), gender: Optional[str] = Form(default=None, description="性别 male/female(必填)"), - hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填),如 1,2,3。female:1-7 male:1-6"), + hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填),如 1,2,3。female:1-7 male:1-7"), beauty_enabled: bool = Form(default=False, description="是否开启美颜(本期不生效)"), use_mask: bool = Form(default=True, description="是否启用 inpaint 遮罩(测试对比用)。false 时用干净原图生成(空遮罩,不烧模板线)"), prompt: str = Form(default="填充遮罩区域的头发", description="ComfyUI 提示词,会替换工作流节点60的文本"), @@ -1210,7 +1210,7 @@ async def hair_grow( return err(1004, "gender 必填且只能为 male / female") # 2. hair_style 必填校验(解析逗号分隔,越界 → 1007) - max_styles = {"female": 7, "male": 6}[gender] + max_styles = {"female": 7, "male": 7}[gender] hair_styles = _parse_hair_styles(hair_style, max_styles) if hair_styles is None: return err(1007, f"hair_style 必填且为 1..{max_styles} 的整数(逗号分隔),收到 {hair_style!r}") @@ -1585,10 +1585,10 @@ async def face_features( --- **入参**(同接口2:先选性别,再多选发型): -- 必填 `gender`(`male`/`female`),决定发型集合(female 7 / male 6)。 +- 必填 `gender`(`male`/`female`),决定发型集合(female 7 / male 7)。 - 必填 `hair_style`(发型序号,逗号分隔如 `1,2,3`),决定返回哪些发际线类型。缺失/越界/非法返回 `1007`。 `female`:1=ellipse,2=flower,3=heart,4=straight,5=wave,6=bigflower,7=clasicalflower; - `male`:1=ellipse,2=inverse_arc,3=m,4=straight,5=heart,6=Softpetal。 + `male`:1=ellipse,2=inverse_arc,3=m,4=straight,5=heart,6=Softpetal,7=wave。 - 可选 `use_mask` / `prompt`:同接口2 的生发控制参数。 注:生发黑模板固定取 `hairline_texture_black/`(middle 档),即三档叠图分别用各自贴图、但生发目标固定 middle。 - 可选 `generate_grow_image`(默认 `true`):是否生成生发效果图(ComfyUI 生发,全流程最耗时)。 @@ -1668,7 +1668,7 @@ async def hairline_generate( image_url: Optional[str] = Form(default=None, description="图片 URL"), image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"), gender: Optional[str] = Form(default=None, description="性别 male/female(必填)"), - hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填,如 1,2,3)。female:1-7 male:1-6"), + hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填,如 1,2,3)。female:1-7 male:1-7"), use_mask: bool = Form(default=True, description="生发是否启用 inpaint 遮罩(同接口2,测试对比用)"), prompt: str = Form(default="填充遮罩区域的头发", description="ComfyUI 提示词(同接口2),会替换工作流节点60的文本"), generate_grow_image: bool = Form(default=True, description="是否生成生发效果图(ComfyUI 生发,最耗时)。默认 true 出图;false 时跳过生发,各发型 grown_image 恒为 null,仅返回三档发际线叠图与中心点"), @@ -1677,7 +1677,7 @@ async def hairline_generate( return err(1004, "gender 必填且只能为 male / female") # hair_style 必填(同接口2):解析逗号分隔,缺失/越界/非法 → 1007 - max_styles = {"female": 7, "male": 6}[gender] + max_styles = {"female": 7, "male": 7}[gender] hair_styles = _parse_hair_styles(hair_style, max_styles) if hair_styles is None: return err(1007, f"hair_style 必填且为 1..{max_styles} 的整数(逗号分隔),收到 {hair_style!r}") diff --git a/docs/实现说明.md b/docs/实现说明.md index fe5d120..0d4e2a9 100644 --- a/docs/实现说明.md +++ b/docs/实现说明.md @@ -68,7 +68,7 @@ 按 `face_ext.obj` 的 UV 把发际线贴图渲染到额头(预览)。生发:黑贴图渲染遮罩 → 调本机 **ComfyUI 8182** 的 `add_hair.json`(Flux-2) 出图。**关键坑**:obj 是重排序,需 `INDEX_MAP_468` 把 MP 序→OBJ 序。 返回 `results[].image_base64` + `grown_image_base64`。 -- `hair_style` 映射:female 1=ellipse 2=flower 3=heart 4=straight 5=wave 6=bigflower 7=clasicalflower;male 1=ellipse 2=inverse_arc 3=m 4=straight 5=heart 6=Softpetal。female 1..5 走「换发型(change_hair)」+Flux-2 重绘管线;female 6/7 与 male 全部走原生发(ComfyUI add_hair)管线。 +- `hair_style` 映射:female 1=ellipse 2=flower 3=heart 4=straight 5=wave 6=bigflower 7=clasicalflower;male 1=ellipse 2=inverse_arc 3=m 4=straight 5=heart 6=Softpetal 7=wave。female 1..5 走「换发型(change_hair)」+Flux-2 重绘管线;female 6/7 与 male 全部走原生发(ComfyUI add_hair)管线。 ### 接口7 C端生发 v2 `/api/v1/hair/grow-v2`(worker)—— 接口2同款,add_hair2 工作流 - **做什么**:与接口 2 完全一致(正面照 + `gender` + `hair_style` 逗号分隔多选 → N 组预览+生发图)。 diff --git a/docs/接口文档.md b/docs/接口文档.md index c4d990d..cf6b0e5 100644 --- a/docs/接口文档.md +++ b/docs/接口文档.md @@ -265,7 +265,7 @@ | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | gender | string | **是** | 性别:`male` / `female`。决定使用的发际线贴图集合 | -| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。越界/非法返回 `1007` | +| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal, 7=wave。越界/非法返回 `1007` | | beauty_enabled | bool | 否 | 生发图是否带美颜效果,默认 false(当前阶段不生效) | | use_mask | bool | 否 | 是否启用 inpaint 遮罩,默认 `true`。`false` 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比 | | prompt | string | 否 | ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本 | @@ -278,7 +278,7 @@ |------|------|------| | image_url | string | 发际线曲线**透明 PNG** URL(仅白色发际线曲线,透明底,**不含人物**,需前端叠加原图显示) | | grown_image_url | string | **生发后图片** URL(ComfyUI/Flux「植发 3 个月」效果图,完整人像照片) | -| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`(male) | +| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`/`wave`(male) | | order | int | 排序序号(当前阶段固定 `1..N`,按贴图顺序,暂不计算合适度) | > ⚠️ 生发图由本机 ComfyUI(Flux-2,端口 8182)生成,**一次请求生成指定发型的 1 张、同步返回**。 @@ -405,8 +405,8 @@ | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| -| gender | string | **是** | 性别:`male` / `female`。决定发型集合(female 7 / male 6)。缺失/非法返回 `1004` | -| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),决定返回哪些发际线类型。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。缺失/越界/非法返回 `1007` | +| gender | string | **是** | 性别:`male` / `female`。决定发型集合(female 7 / male 7)。缺失/非法返回 `1004` | +| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),决定返回哪些发际线类型。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal, 7=wave。缺失/越界/非法返回 `1007` | | use_mask | bool | 否 | 生发是否启用 inpaint 遮罩,默认 `true`。`false` 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比 | | prompt | string | 否 | ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本 | | generate_grow_image | bool | 否 | 是否生成生发效果图(ComfyUI 生发,全流程最耗时),默认 `true`。传 `false` 时跳过生发,各发型 `grown_image_*` 恒为 `null`,仅返回三档发际线叠图与中心点,可大幅降低耗时 | @@ -427,7 +427,7 @@ | 字段 | 类型 | 说明 | |------|------|------| -| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`(male) | +| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`/`wave`(male) | | image_middle_url | string | middle 档发际线曲线**透明 PNG** URL(仅曲线,透明底,**不含人物**,需叠加原图显示) | | image_high_url | string | high 档发际线曲线**透明 PNG** URL(同上,high 档曲线) | | image_low_url | string | low 档发际线曲线**透明 PNG** URL(同上,low 档曲线) | diff --git a/hairline/service.py b/hairline/service.py index 78edb8f..d0963ec 100644 --- a/hairline/service.py +++ b/hairline/service.py @@ -46,7 +46,8 @@ _FEMALE_KEY_TO_CHANG = { _HAIRSTYLE_ORDER = { "female": ["ellipse", "flower", "heart", "straight", "wave", "bigflower", "clasicalflower"], # 1..7 - "male": ["ellipse", "inverse_arc", "m", "straight", "heart", "Softpetal"], # 1..6 + "male": ["ellipse", "inverse_arc", "m", "straight", "heart", "Softpetal", + "wave"], # 1..7 } _REPO = os.path.dirname(os.path.dirname(__file__)) @@ -227,7 +228,7 @@ def generate_grow_results(image_bgr: np.ndarray, gender: str, use_mask: bool = T unet_name: str | None = None): """指定发际线类型:发际线透明叠图(白线 RGBA) + 生发图(ComfyUI)。 - hair_styles(1-indexed 列表):指定生成哪几张发际线(按贴图排序)。female: 1..7,male: 1..6。 + hair_styles(1-indexed 列表):指定生成哪几张发际线(按贴图排序)。female: 1..7,male: 1..7。 为 None 时生成全部(兼容旧调用)。 use_mask(默认 True):是否启用 inpaint 遮罩,用于测试对比(同接口3)。 False 时用**干净原图 + 空遮罩**送 ComfyUI(不烧黑色模板线)。 diff --git a/hairline_texture/man_wave.png b/hairline_texture/man_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..ad9f0ab0c8ba2e405d393fd2792a7b1675d561c7 GIT binary patch literal 6487 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 CGjm)3 literal 0 HcmV?d00001 diff --git a/hairline_texture_black/man_wave.png b/hairline_texture_black/man_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..9d5c3572678815580d96f23efbe36fc5b69126f3 GIT binary patch literal 4366 zcmeHL`%}}$7T%?F z_SwBP5KMw^pf3RTO4h8#8X5Sy^M}LFhmhmXUyS`a4t$!JkP=&Quk3A2~ZcXu=yA2(%{>t+>1--Ad zdmHwO)8UDnij2KB()-Rm&}?z>nz_JG?@hq+GXMys-T00FMUE%{@-c>6Z7>{o#9;le z2-5;H`8$2i!-r$ZwA1927V$Oi82QFb&zl*UMCz)Xk^EkgpOD=$zI8u2f709jsXk$0 za;8mP{Y0d2xPhpoO+P1ulW8Ll>=oyANy|Oia6nw1_sfkX$cn{YY4iAa6Sv4l!zea>ig{FlS@xraW}i@q1Hujpe)r@w29dc}=u=ZoEG z@ighl2ZDyFD7OCoiU%TCL6Y_kdHC<^%|&9KOJ&ccG0IkfzcjZOVRt!nB9V(t!~I6d zWhlBVF_R)X#j>7G=wxT>Z?$l5$dG##TtX^59}~b{ku1X!Wn&+g&?NS7OPgMx#B4Hs zR0`yj_T=hRH$t5u`LaP;Tww}MF= z64}*`1!p+rTUW`k9144?NVqc+>Cm0#;?A{|SBNP)))O|N2)D!Fek?g|j#ek8xcFq2 z!og@7;=#?`H5L_!=<;?vbp)3NNeE$>rhl%oiV;)Bkm?HJ3xSI+nO5_9S_$3J_o>WE zgMekVcu_7RMHJffQ*tbOvvOy<-srS+L0w$XWsTYa=5N-Cz22v7Z zQ<;F6zK$tsFniO^?&1bEnx$R?#1nb-I+LV9y;pbLI(+O2Y+5k}6c5}zqw10OXSJ4V z6qmd)T0cKo(kO%y{%)(7yVVeu*5U8^@hYt9EV&_b`$-L*b}(2ZoDMMfSwGskHi#2l zAFtLvQAs;(Ty4$cp3o&90^R}L7m6r*A1kdcm7tJAY#;P^7eZE@df{Jwtu- z(rh^6dkIY2#Y;_TQ7g6HUn9J%PThRK%Kh=Y+H~16hqxalWKWxPRy`?ri9DY-A)xUA ztz#BiY1moEn>HriK+AtuC6C;LN(++~4A(tLxT|?PP~@3XzR)-t5?GqDm+ZRJE5Sh_ zNC=(#8ORT-MSO?bTF%oDV{KG1Q_D({7oA|I6I8x?H7^fIEzcQ2bSpI~tMlE;^@4#> zU!>8lo_MwDNus_Te%a~71oDW&>=h|fo1c`!%Gf1u55uYY3X1MGIa`5Vca5)C1~-r1 z;p$oeP3;?cd0YjzM4Gsng7^;4ttB70;f{=iqy` zfk&JX8d*@ZOem!?AUliFqu|?&F$)T52Ll~~r4!+;OBp8#_k%dFJFx}yH~~M-2wrUR zmF=_Nd?A#jg8zjM4O4ft07LabYdJY{0$2J8_E`62&EsG!odDm_N1}4Y4p7@JsPK#_ zhHyPv)p=n$6qU;k(x|fiYNQau7hs0D3fUt(k;Niu(kC;@a1Sye$6uu*53M4XP3+#) zF0s5?C&EnWfI27B_~G%^!qzaj@EP|m9;H-2R}-?66QqQi4lHd&Y|7A>PC}S+jZE@wegG~B1%io ziy1^COXUKQ1I09C{QzwonpAEFsiU3c6|-D7XzEWA@|wh5>KN~JSM{es;kS#j8}a@#0e;gnyc>yy|MBUrlaAN>>X`SQ1UavSy8A^v8IkyK5b zyS&`sG}m>Z1^*bM;>Gl5$wIXyIGMa-P$!%z%O(yCS}s>n0wKAXx@DQ_DorwhQhg)I z4$n+`aaQ2un}LwkHpzR>2Bp24T2(39e7bKbJA5ED?u?#`P)HXjd-z) zR)UuO1QyIQPnnN0)S*G9bT?&*g7efu9=BG#x@GxveDpz78Y;*YO?m7?XW)h?$=>e9 zTDa*W2H??sx`_JRuQ7)922*XTQ%&kjzxzHDd-f1A8 z6qe`hkRCr^fa!%={hz|9IK%c|JJ=6uk&jV;&>A*tm}dRF^i_cFVL*^60N8B+IQ{?t zo$y|G{~qtt;e9o{ZwCKIy>Q@$dMO+bexjkS#T5oWwSFWtd{=;@hmRd<^do-rH&Gen A(f|Me literal 0 HcmV?d00001 diff --git a/hairline_texture_high/man_wave.png b/hairline_texture_high/man_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..117fe9f767e0d849a5cbde4ca82cd74b53dbf5f1 GIT binary patch literal 6517 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 X;u;uG%Wg@|D#^3L;{xFv;_m+dvmGz2 literal 0 HcmV?d00001 diff --git a/hairline_texture_low/man_wave.png b/hairline_texture_low/man_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..3c563c0ff462b2d8f8e6b54daeab9cf5de84d109 GIT binary patch literal 6521 zcmeHM_gj-m*PevX35cR}(Qj2`1p^k~1tp;JqM}k%IwY(Mp@WhDQc^@kq`9kt;!+kw zqEtn?kN__1D+&ezQCh&Pl!Ox2gkak9<^3PN-@g6fx#r9~GuNDZu5+LJ%r)7b7u=8< zMj8MB?x!2ut*KI|1s4OqLWK z1kUBW3ji+*G^L@+ioQ19)enC$J{+GMdMyn6I}#TgTKcl^3IGOzGpAfGrNCCEHEY9s z{Z;t{O^rJ{()n?b3t2|-j$bWF91=ce2zHzGB9U|sZ^uh=>vRq8Z+fKFLN0DEVf zd$J&t(w)Nh)Jk{S1KT(^4yU%|=rQOyRkLC!7q)yqOuhNAjGaHBOE~vgw2Su2Z1}?~ zM=sLK%;qqVxB{|_F(kl@b3-bN!ja;WPXays>e0U|DbgRi5<}CL4i|S{ z3K!XN4om%U63&_-iTzq<(v%Regi}t^$Nm5ZG0%`v^M}n!P%WjacnFb;DI3zj-*2d9 zWBTaqhfZ2S-aAeiZ+aYzuHGD=-CvsRM&o2pgkGbw*4ps+JM8Htx7n zsDlCdiqx5(GgXVmkeQ-`yv(?sj1h1sf;#Mb@Ei+PLam*}tnh&kh zM9NN!S?cT0J}h62Eb|c|-q^^yFKSvZc8kogYxHY)Ch1i04#IWj_DYUjK(L1-IZ)?t~AkxubgwS=nL3z2b#Bn03aKTsd@SVl=7|cWrrs#``PD zmUbCE7+gg^MFA?*a5(Dp_TB#XlMIQDryD0hsL6l^$)eWV5qOPgqEW;*=nJ zwR0!wd3AAj#n+HhA7PpbdRiO~M7e$5XN;g+z1-PB+yJk(fpR0Hyr_i& zz4F>Z&4i3wf0|{_;;#R!sidE)0_DN!3AKl}k=if2V2|)gY5mSC$BJ3X^=PqgGhElKuQ>uj3jKVEB#<0zPx669&;Ha)@(_VTbu_BIwI zzlLQv+!>mtqsNIG7dt$W!|=A$!0SpJOt@wBHV|&rCHF9N=shimcE!nLH$is;Bcl=WpnToSi(?GFJv;Vk91AZ6ze z0>7Y-T{Jc*RS~WiRbB}2_iwL#|9G>#%p^f$EP1jdP){yp{0^S$LB0}&n zqMgvE7x!Q+12#(JGdEjl9rVAqf8B6urlMNxeAX%^eOTt1m4QC{w< zO6W%>OfP?+aO90dTgnHDWlZzwmuMSwzIV=44pfqdWY@|i?vPPw?{UkOnr zYBQ7Vm+pPt4H|#zAhtp&e6ymSvd3IJsa2kc=;uZc==-I^!C*B~j&lp1g42&6q(4!R zc-i^P?vEe3h3j-T%_c=MEp%tGCn5IaENOi|LMszW)L71nV@u#%$vg z>1ls0)%}{)xobcMYSA3hw^oKhzw6rAib zNvLdwu3|bm1$J8}{KcI=mf8)MJvx0B4sxFJ8rYDGirLSLk9ABBMvsWLtB|xG*3+~a zZ<9^Kn%7K3zc-Z{GeN@4qTgC?TPM+Ujqyz*MnSPZMue?`<1a5~9D9>hus@nTSnXOZ zeg+RL=b?}CAH3SI?M=f(4MgsGL>#VVB^SK7ooS?zq^TOCt62I`MPBrvS&3x98KSl>8`OZpYfj^(gly=89h!;+QSEB zmmrVZ)yhl8smvL2u(>#UGWe+tIpNfspv*Z)-!BFukx=X;5vGgBZi7hPmK`IH)-f(N>@P(r8=4F!gBcg1Yn&S@H z43KnJzTAK}se>3=(ru{8OXqHC0JHBbtsZlpo#U2UYUa>q?2hJ_#m(aUUrSWAD6@}} zOiG^&A!3;EERc}KG_B*R^d_Hj{EnqGBS6aqd<5ZxoKj^rYvzy|q$&?xkYmS-<%0Jl zdkz$>g!aeFaN1g-vu#PoT53y74JO`|j;NA%BeV*V-MXd^87ibT>jM4~;a&r7qi>zE zQnlV8!yA$8<2J@?0|@0a-#n;ElCyzl;O-?1fG=ttx2IoAzV5D!mG zJiL{Q02>~TlO&g#^~XdDNpcI?U}yuC+d&;`XQ&7Jkx%ZMSib*-KS32=Hze%C8b}9z zpDi9?+w*=qVG9S6@u5wR{8Z=9DHFtT;rGkOJKGvfd00{?-d2A*Ht>`r<0ljO9+ zH8<0_tE```_i77xWaW@kmfdGoNHm9Pmt=G6b`^3PZX)Bl)E74I^O~2czM59C8t9Wr zx7T`ecw#+E(@+i6>X*Dti+he&Kw(DiYCt<+sLNjV0noMxue^CDOX$XXlUVy$; zG;C6O6}N_KHLW7kA?d(j&~Qx^{pa2Z>G`Yn1nDJ5c?5GaHj2m7v47QG?t%V#D8*UH4{G--!p| zysh+64R=@Y=hEjYw8X3iDJLkOwz>fC*2^lXtnTm`c&zMq5bk`4K{oRdr;!`3J8&_T zb5J~N|JTg>4LtP|rqVJmKO?xa6Ur(Y&8&XmNMiefcQgLv8V>&@<6<9?T>bXUTMxa$ z8{ppQBU7pW!Avt8&n+QcW@STiN;c_EM|p25&ks)jHAh8UZvW;*?S=0}uNtbFV09_YK{x z4%{t`=I^^h?K1??YRV`k_ARb|mJ|;AbV{&|efOlyvoY|USfXTNC_J$nYonM>jr*9L zdi9vJiW=H9lw!IzG7`^+eX3T26%EV{S9TxIuy~;@CtR8R<<_l3wF|X+g(r^mnm-^m zVPq-n&K7YugA-jjvjZuHH0ZE9@~SwHetk(&>NF}WH-R@#yAL5Y*#%?v(^=Cf@aLN1EGx|$n&^8kK$hQZp7EKcRl z%eFf=qfZ{M79dAwb*3yBYs+04<${bsMa_6+<;qZOt6n%!9pqRV&2hf)N4-Rr#yaxW zhjLpQPM>`8X)rwH#FC_J-J8Be#mP)I^!?WLy}+^}B1MFf`IBPF9HA^SV;`4Yp*!OZ zv|sLkhj@xTG)>mj4f2JBy$h$z@E1d8)IiQ2qrmBuZ*Qrou@F9y-NwzIE@3PtZ6{kX z55m&pmQZ%3aay$n4LM?Ofm_jz`E1arRzVq~$jvLc=HJJj9uH=l-EfYLDZ6`nqf8n5 zng*Afi|e8_vT}fRe8oD`MfQn$<=ygO*<5?-GsvGOrN4=kJmkI)TN!xf ztD0MI6a?wYKIPq7*$3X=Z|Q_SjhHXw*>0|6i=&vn6^!(1@c#MY=uU5OmpdCXj#AIH z(;Cma!N!;U8oL*~&y3hZ5XA)Z8b;-#7V`BtD7EIpaK}>>KRpI*Oy;g*C392rz=3B2 z4o%;!GNxL#0PX4s17Y8zRp0T3Zyu`hj@uizBJ_Oq$;!+Nc<#QQb*r1zzFPlHqu zi=qv^mKz|U?RCHBwyVeE@IRDszeIpeP5Rb|R$ZqT@4NH(_{j3{4yR`drKLj zgga_rl3I6bED)DZTI1NIXC$(oH>9#^qc!QjM!6UJwz`+{)EU$NMtP{FHZcR8!6y~P zHX%C_3zpm~2MF(YFBBm3$a^NbKz*e7X<_EA)etd^G=+AMu;Fm}j%b!phbJAi6O@N2 zrTHJZIjP}%Vr47+Nnn}3oijT_Y~`wE{}e&C+8X~w99|dgD-^TVCy0i}>v;jbk5*L| zT}k#a@HczKjESt7s>Z#Fncm4YEnBP~?PDq8qS-wNgy+a#&YW%Yc`T?lQS3PWB7SNu zx*%(*Mm*Iz^@k1?YDe%tZUZfz$2$v{0jknDQBZu$)%#6Eplt`k^2YKqgrfAC^F;7| z+vtzr-rx*x6h{6T0l?|g0FZC~WBhXn|3tz+Eck~7|FGcyiUmFu9g1g$zo8u}GMm%e T<}4L2BjAkdg;Vt>us8k}1fq?l literal 0 HcmV?d00001 diff --git a/static/test_interface2.html b/static/test_interface2.html index 6e0d5dd..155088b 100644 --- a/static/test_interface2.html +++ b/static/test_interface2.html @@ -134,7 +134,7 @@ const API_BASE = window.location.origin; let _origUrl = ''; const TYPE_LABELS = { - ellipse:'椭圆形', flower:'花瓣形', heart:'心形', straight:'直线形', wave:'波浪形', m:'M形', inverse_arc:'倒弧形' + ellipse:'椭圆形', flower:'花瓣形', heart:'心形', straight:'直线形', wave:'波浪形', m:'M形', inverse_arc:'倒弧形', Softpetal:'柔和花瓣形', bigflower:'大花瓣型', clasicalflower:'古典花瓣型' }; function $(id) { return document.getElementById(id); } @@ -247,6 +247,7 @@ const HAIR_STYLES = { { value:'4', label:'straight 直线形' }, { value:'5', label:'heart 桃心形' }, { value:'6', label:'Softpetal 柔和花瓣形' }, + { value:'7', label:'wave 波浪形' }, ] }; diff --git a/static/test_interface5.html b/static/test_interface5.html index 08b6f3d..d699640 100644 --- a/static/test_interface5.html +++ b/static/test_interface5.html @@ -101,7 +101,7 @@
- +
@@ -122,7 +122,7 @@
-
JPG/PNG 正面照  |  Female: 椭圆/花瓣/心形/直线/波浪  |  Male: 椭圆/倒弧/M形/直线  |  每个发型返回 middle/high/low 三档 + 生发图
+
JPG/PNG 正面照  |  Female: 椭圆/花瓣/心形/直线/波浪/大花瓣/古典花瓣  |  Male: 椭圆/倒弧/M形/直线/桃心/柔和花瓣/波浪  |  每个发型返回 middle/high/low 三档 + 生发图
@@ -184,6 +184,7 @@ const HAIR_STYLES = { { value:'4', label:'4. straight 直线' }, { value:'5', label:'5. heart 桃心形' }, { value:'6', label:'6. Softpetal 柔和花瓣形' }, + { value:'7', label:'7. wave 波浪形' }, ] };