LittleMouse commited on
Commit
244baf9
·
1 Parent(s): 436743e
.gitattributes CHANGED
@@ -33,3 +33,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ unet.axmodel filter=lfs diff=lfs merge=lfs -text
37
+ vae_decoder.axmodel filter=lfs diff=lfs merge=lfs -text
38
+ *.axmodel filter=lfs diff=lfs merge=lfs -text
39
+ **/*.axmodel filter=lfs diff=lfs merge=lfs -text
40
+ **/*.onnx filter=lfs diff=lfs merge=lfs -text
41
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ log_2025.json
6
+ # C extensions
7
+ *.so
8
+ *.log
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # Ruff stuff:
171
+ .ruff_cache/
172
+
173
+ # PyPI configuration file
174
+ .pypirc
README.md CHANGED
@@ -1,3 +1,89 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ base_model:
4
+ - stable-diffusion-v1-5/stable-diffusion-v1-5
5
+ ---
6
+
7
+ # Dark-Sushi-Mix-v1.5 on LLM8850
8
+
9
+ 原模型地址:https://civitai.com/models/24779?modelVersionId=93208
10
+ 当前为 **10 步扩散版本**,固定延迟 20×250 ms ≈ 5 s。
11
+
12
+ ---
13
+
14
+ ## 1. 手动运行(开发调试)
15
+
16
+ | 步骤 | 命令 |
17
+ |------|------|
18
+ | 启动后端 | `uvicorn api_10steps:app --host 0.0.0.0 --port 7888` |
19
+ | 命令行生图 | `python gen_img.py` |
20
+ | Web 界面 | `cd client && python app.py` 后访问 http://127.0.0.1:5000 |
21
+
22
+ ---
23
+
24
+ ## 2. 端侧一键自启(生产部署)
25
+
26
+ > 开机后自动完成:
27
+ > ① 启动后端 → ② 启动前端 → ③ 自动打开 Firefox 全屏展示 http://localhost:5000/
28
+
29
+ ### 2.1 一键启用
30
+
31
+ 仓库根目录已内置脚本,直接执行:
32
+
33
+ ```bash
34
+ # 复制并设置启动脚本
35
+ sudo cp sd-launch.sh /opt/sd-launch.sh
36
+ sudo chmod +x /opt/sd-launch.sh
37
+
38
+ # 创建用户级自启动
39
+ mkdir -p ~/.config/autostart
40
+ cp sd-launch.desktop ~/.config/autostart/
41
+
42
+ # 确保 Firefox 已安装
43
+ sudo apt update && sudo apt install firefox -y
44
+ ```
45
+
46
+ ### 2.2 文件说明
47
+
48
+ - `sd-launch.sh`
49
+ 统一启动脚本:切目录 → 后台启动后端 → 后台启动前端 → 等待端口 → 使用 Firefox kiosk 模式自动全屏打开。
50
+
51
+ - `sd-launch.desktop`
52
+ 用户级自启动配置,在图形界面登录后自动执行脚本。
53
+
54
+ ---
55
+
56
+ ## 3. 日志与维护
57
+
58
+ | 操作 | 命令 |
59
+ |------|------|
60
+ | 查看启动日志 | `tail -f /var/log/sd-launch/startup.log` |
61
+ | 查看后端日志 | `tail -f /var/log/sd-launch/backend.log` |
62
+ | 查看前端日志 | `tail -f /var/log/sd-launch/frontend.log` |
63
+ | 查看浏览器日志 | `tail -f /var/log/sd-launch/browser.log` |
64
+ | 手动重启 | `pkill -f sd-launch.sh && /opt/sd-launch.sh &` |
65
+ | 停止服务 | `pkill -f uvicorn && pkill -f "python3 app.py" && pkill firefox` |
66
+
67
+ ---
68
+
69
+ ## 4. 常见问题
70
+
71
+ - **Firefox 没有自动打开**
72
+ 确保已安装 Firefox:`sudo apt install firefox -y`
73
+ - **重启后服务没启动**
74
+ 检查 `~/.config/autostart/sd-launch.desktop` 是否存在
75
+ - **端口冲突**
76
+ 修改脚本中的 `7888` / `5000` 端口即可
77
+ - **手动测试浏览器**
78
+ 运行:`firefox --kiosk http://localhost:5000/`
79
+
80
+ ---
81
+
82
+ ## 5. 验证部署
83
+
84
+ 重启系统后,应该看到:
85
+ 1. 自动启动后端服务(端口 7888)
86
+ 2. 自动启动前端服务(端口 5000)
87
+ 3. Firefox 自动全屏打开 SD 生图界面
88
+
89
+ 至此,AX650 端侧即可实现 **插电即跑** 的 Dark-Sushi-Mix-v1.5 体验。
api_10steps.py ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Response
2
+ from pydantic import BaseModel
3
+ from contextlib import asynccontextmanager
4
+ import numpy as np
5
+ from PIL import Image
6
+ import io
7
+ import uuid
8
+ from typing import List, Union
9
+
10
+ import axengine
11
+ import torch
12
+
13
+ from transformers import CLIPTokenizer, PreTrainedTokenizer
14
+ import time
15
+ import argparse
16
+
17
+ import os
18
+ import traceback
19
+ from diffusers import DPMSolverMultistepScheduler
20
+ # 配置日志格式
21
+ DEBUG_MODE = True
22
+ LOG_TIMESTAMP = True
23
+
24
+ def debug_log(msg):
25
+ if DEBUG_MODE:
26
+ timestamp = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] " if LOG_TIMESTAMP else ""
27
+ print(f"{timestamp}[DEBUG] {msg}")
28
+
29
+ # 服务配置
30
+ MODEL_PATHS = {
31
+ "tokenizer": "./models/tokenizer",
32
+ "text_encoder": "./models/text_encoder/sd15_text_encoder_sim.axmodel",
33
+ "unet": "./models/unet.axmodel",
34
+ "vae": "./models/vae_decoder.axmodel",
35
+ "time_embeddings": "./models/time_input_dpmpp_20steps.npy" # 仍使用20步数据,但只取其中10步
36
+ }
37
+
38
+ class DiffusionModels:
39
+ def __init__(self):
40
+ self.models_loaded = False
41
+ self.tokenizer = None
42
+ self.text_encoder = None
43
+ self.unet = None
44
+ self.vae = None
45
+ self.time_embeddings = None
46
+
47
+ def load_models(self):
48
+ """预加载所有模型到内存"""
49
+ try:
50
+ # 初始化tokenizer和模型
51
+ self.tokenizer = CLIPTokenizer.from_pretrained(MODEL_PATHS["tokenizer"])
52
+ self.text_encoder = axengine.InferenceSession(MODEL_PATHS["text_encoder"])
53
+ self.unet = axengine.InferenceSession(MODEL_PATHS["unet"])
54
+ self.vae = axengine.InferenceSession(MODEL_PATHS["vae"])
55
+
56
+ # 加载时间嵌入并间隔采样为10步
57
+ full_time_embeddings = np.load(MODEL_PATHS["time_embeddings"])
58
+ # 从20步中间隔取10步 (取索引 0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
59
+ self.time_embeddings = full_time_embeddings[::2] # 间隔取值
60
+ debug_log(f"时间嵌入已从20步采样为10步,形状: {self.time_embeddings.shape}")
61
+
62
+ self.models_loaded = True
63
+ print("所有模型已成功加载到内存")
64
+ except Exception as e:
65
+ print(f"模型加载失败: {str(e)}")
66
+ raise
67
+
68
+ diffusion_models = DiffusionModels()
69
+
70
+ @asynccontextmanager
71
+ async def lifespan(app: FastAPI):
72
+ # 服务启动时加载模型
73
+ diffusion_models.load_models()
74
+ yield
75
+ # 服务关闭时清理资源
76
+ # (根据axengine的要求添加必要的清理逻辑)
77
+
78
+ app = FastAPI(lifespan=lifespan)
79
+
80
+ class GenerationRequest(BaseModel):
81
+ positive_prompt: str
82
+ negative_prompt: str = ""
83
+ # 移除这些参数,因为已经固定
84
+ # num_inference_steps: int = 10 # 固定为10步
85
+ # guidance_scale: float = 5.4 # 固定为5.4
86
+ seed: int = None
87
+
88
+ @app.post("/generate")
89
+ async def generate_image(request: GenerationRequest):
90
+ try:
91
+ # 输入验证
92
+ if len(request.positive_prompt) > 1000:
93
+ raise ValueError("提示词过长")
94
+
95
+ # 执行推理流程 - 固定参数
96
+ image = generate_diffusion_image(
97
+ positive_prompt=request.positive_prompt,
98
+ negative_prompt=request.negative_prompt,
99
+ num_steps=10, # 固定10步
100
+ guidance_scale=5.4, # 固定CFG=5.4
101
+ seed=request.seed
102
+ )
103
+
104
+ # 转换图像为字节流
105
+ img_byte_arr = io.BytesIO()
106
+ image.save(img_byte_arr, format='PNG')
107
+
108
+ return Response(content=img_byte_arr.getvalue(), media_type="image/png")
109
+
110
+ except Exception as e:
111
+ error_id = str(uuid.uuid4())
112
+ print(f"Error [{error_id}]: {str(e)}")
113
+ raise HTTPException(
114
+ status_code=500,
115
+ detail=f"生成失败,错误ID:{error_id}"
116
+ )
117
+
118
+
119
+
120
+ def get_embeds(prompt, negative_prompt):
121
+ """获取正负提示词的嵌入(带形状验证)"""
122
+ try:
123
+ debug_log(f"开始处理提示词: {prompt}")
124
+ start_time = time.time()
125
+
126
+
127
+ def process_prompt(prompt_text):
128
+ inputs = diffusion_models.tokenizer(
129
+ prompt_text,
130
+ padding="max_length",
131
+ max_length=77,
132
+ truncation=True,
133
+ return_tensors="pt"
134
+ )
135
+ debug_log(f"Tokenizer输出形状: {inputs.input_ids.shape}")
136
+
137
+ outputs = diffusion_models.text_encoder.run(None, {"input_ids": inputs.input_ids.numpy().astype(np.int32)})[0]
138
+ debug_log(f"文本编码器输出形状: {outputs.shape} | dtype: {outputs.dtype}")
139
+ return outputs
140
+
141
+ neg_start = time.time()
142
+ neg_embeds = process_prompt(negative_prompt)
143
+ pos_embeds = process_prompt(prompt)
144
+ debug_log(f"文本编码完成 | 耗时: {(time.time()-start_time):.2f}s")
145
+
146
+ # 验证形状
147
+ if neg_embeds.shape != (1, 77, 768) or pos_embeds.shape != (1, 77, 768):
148
+ raise ValueError(f"嵌入形状异常: 负面{neg_embeds.shape}, 正面{pos_embeds.shape}")
149
+
150
+ return neg_embeds, pos_embeds
151
+ except Exception as e:
152
+ print(f"获取嵌入失败: {str(e)}")
153
+ traceback.print_exc()
154
+ exit(1)
155
+
156
+
157
+ def generate_diffusion_image(
158
+ positive_prompt: str,
159
+ negative_prompt: str,
160
+ num_steps: int = 10, # 固定默认值为10
161
+ guidance_scale: float = 5.4, # 固定默认值为5.4
162
+ seed: int = None
163
+ ) -> Image.Image:
164
+ """
165
+ 生成扩散图像的优化版本(固定10步推理,CFG=5.4)
166
+
167
+ 参数:
168
+ positive_prompt (str): 正向提示词
169
+ negative_prompt (str): 负向提示词
170
+ num_steps (int): 推理步数 (固定为10)
171
+ guidance_scale (float): 分类器自由引导系数 (固定为5.4)
172
+ seed (int): 随机种子 (可选)
173
+
174
+ 返回:
175
+ PIL.Image.Image: 生成的图像
176
+
177
+ 异常:
178
+ ValueError: 输入参数无效时抛出
179
+ RuntimeError: 推理过程中出现错误时抛出
180
+ """
181
+ try:
182
+ # 参数验证和固定
183
+ if not positive_prompt:
184
+ raise ValueError("正向提示词不能为空")
185
+
186
+ # 强制使用优化后的固定参数
187
+ num_steps = 10
188
+ guidance_scale = 5.4
189
+
190
+ debug_log(f"开始生成流程 (固定参数: 10步, CFG=5.4)...")
191
+ start_time = time.time()
192
+
193
+ # =====================================================================
194
+ # 1. 初始化配置
195
+ # =====================================================================
196
+ seed = seed if seed is not None else int(time.time() * 1000) % 0xFFFFFFFF
197
+ torch.manual_seed(seed)
198
+ np.random.seed(seed)
199
+ debug_log(f"初始随机种子: {seed}")
200
+
201
+ # =====================================================================
202
+ # 2. 文本编码 (保持原有输入形状 [1, 77, 768])
203
+ # =====================================================================
204
+ embed_start = time.time()
205
+ neg_emb, pos_emb = get_embeds(
206
+ positive_prompt,
207
+ negative_prompt,
208
+ )
209
+ debug_log(f"文本编码完成 | 耗时: {time.time()-embed_start:.2f}s")
210
+
211
+ # =====================================================================
212
+ # 3. 初始化潜在变量 (固定形状 [1, 4, 60, 40])
213
+ # =====================================================================
214
+ scheduler = DPMSolverMultistepScheduler(
215
+ num_train_timesteps=1000,
216
+ beta_start=0.00085,
217
+ beta_end=0.012,
218
+ beta_schedule="scaled_linear",
219
+ algorithm_type="dpmsolver++",
220
+ use_karras_sigmas=True
221
+ )
222
+ scheduler.set_timesteps(num_steps) # 设置为10步
223
+
224
+ latents_shape = (1, 4, 60, 40)
225
+ latent = torch.randn(latents_shape, generator=torch.Generator().manual_seed(seed))
226
+ latent = latent * scheduler.init_noise_sigma
227
+ latent = latent.numpy().astype(np.float32)
228
+ debug_log(f"潜在变量初始化 | 形状: {latent.shape} sigma:{scheduler.init_noise_sigma:.3f}")
229
+
230
+ # =====================================================================
231
+ # 4. 准备时间嵌入 (使用预处理的10步数据)
232
+ # =====================================================================
233
+ if len(diffusion_models.time_embeddings) != num_steps:
234
+ raise ValueError(f"时间嵌入步数不匹配: 需要{num_steps}步 当前{len(diffusion_models.time_embeddings)}步")
235
+ time_steps = diffusion_models.time_embeddings
236
+ debug_log(f"使用预处理的10步时间嵌入,形状: {time_steps.shape}")
237
+
238
+ # =====================================================================
239
+ # 5. 采样主循环 (10步优化版)
240
+ # =====================================================================
241
+ debug_log("开始10步采样循环...")
242
+ for step_idx, timestep in enumerate(scheduler.timesteps.numpy().astype(np.int64)):
243
+ step_start = time.time()
244
+
245
+ # 准备时间嵌入 (形状 [1, 1])
246
+ time_emb = np.expand_dims(time_steps[step_idx], axis=0)
247
+
248
+ # -----------------------------------------
249
+ # UNET双推理流程 (CFG=5.4优化)
250
+ # -----------------------------------------
251
+ # 负面提示推理
252
+ noise_pred_neg = diffusion_models.unet.run(None, {
253
+ "sample": latent,
254
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
255
+ "encoder_hidden_states": neg_emb
256
+ })[0]
257
+
258
+ # 正面提示推理
259
+ noise_pred_pos = diffusion_models.unet.run(None, {
260
+ "sample": latent,
261
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
262
+ "encoder_hidden_states": pos_emb
263
+ })[0]
264
+
265
+ # CFG融合 (固定使用5.4的引导强度)
266
+ noise_pred = noise_pred_neg + 5.4 * (noise_pred_pos - noise_pred_neg)
267
+
268
+ # 转换为Tensor
269
+ latent_tensor = torch.from_numpy(latent)
270
+ noise_pred_tensor = torch.from_numpy(noise_pred)
271
+
272
+ # 调度器更新
273
+ scheduler_start = time.time()
274
+ latent_tensor = scheduler.step(
275
+ model_output=noise_pred_tensor,
276
+ timestep=timestep,
277
+ sample=latent_tensor
278
+ ).prev_sample
279
+ debug_log(f"调度器更新完成 | 耗时: {(time.time()-scheduler_start):.2f}s")
280
+
281
+ # 转换回numpy
282
+ latent = latent_tensor.numpy().astype(np.float32)
283
+ debug_log(f"更新后潜在变量范围: [{latent.min():.3f}, {latent.max():.3f}]")
284
+
285
+ debug_log(f"步骤 {step_idx+1}/{num_steps} | 耗时: {time.time()-step_start:.2f}s")
286
+
287
+ # =====================================================================
288
+ # 6. VAE解码 (强制输出形状为768x512)
289
+ # =====================================================================
290
+ debug_log("开始VAE解码...")
291
+ vae_start = time.time()
292
+ latent = latent / 0.18215
293
+ image = diffusion_models.vae.run(None, {"latent": latent})[0]
294
+
295
+ # 转换为PIL图像 (优化内存拷贝)
296
+ image = np.transpose(image.squeeze(), (1, 2, 0))
297
+ image = np.clip((image / 2 + 0.5) * 255, 0, 255).astype(np.uint8)
298
+ pil_image = Image.fromarray(image[..., :3]) # 移除alpha通道
299
+ pil_image.save("./api.png")
300
+ debug_log(f"VAE解码完成 | 耗时: {time.time()-vae_start:.2f}s")
301
+ debug_log(f"总耗时: {time.time()-start_time:.2f}s (10步优化版)")
302
+ return pil_image
303
+
304
+ except Exception as e:
305
+ error_msg = f"生成失败: {str(e)}"
306
+ debug_log(error_msg)
307
+ traceback.print_exc()
308
+ raise RuntimeError(error_msg)
api_server.py ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Response
2
+ from pydantic import BaseModel
3
+ from contextlib import asynccontextmanager
4
+ import numpy as np
5
+ from PIL import Image
6
+ import io
7
+ import uuid
8
+ from typing import List, Union
9
+
10
+ import axengine
11
+ import torch
12
+
13
+ from transformers import CLIPTokenizer, PreTrainedTokenizer
14
+ import time
15
+ import argparse
16
+
17
+ import os
18
+ import traceback
19
+ from diffusers import DPMSolverMultistepScheduler
20
+ # 配置日志格式
21
+ DEBUG_MODE = True
22
+ LOG_TIMESTAMP = True
23
+
24
+ def debug_log(msg):
25
+ if DEBUG_MODE:
26
+ timestamp = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] " if LOG_TIMESTAMP else ""
27
+ print(f"{timestamp}[DEBUG] {msg}")
28
+
29
+ # 服务配置
30
+ MODEL_PATHS = {
31
+ "tokenizer": "./models/tokenizer",
32
+ "text_encoder": "./models/text_encoder/sd15_text_encoder_sim.axmodel",
33
+ "unet": "./models/unet.axmodel",
34
+ "vae": "./models/vae_decoder.axmodel",
35
+ "time_embeddings": "./models/time_input_dpmpp_20steps.npy"
36
+ }
37
+
38
+ class DiffusionModels:
39
+ def __init__(self):
40
+ self.models_loaded = False
41
+ self.tokenizer = None
42
+ self.text_encoder = None
43
+ self.unet = None
44
+ self.vae = None
45
+ self.time_embeddings = None
46
+
47
+ def load_models(self):
48
+ """预加载所有模型到内存"""
49
+ try:
50
+ # 初始化tokenizer和模型
51
+ self.tokenizer = CLIPTokenizer.from_pretrained(MODEL_PATHS["tokenizer"])
52
+ self.text_encoder = axengine.InferenceSession(MODEL_PATHS["text_encoder"])
53
+ self.unet = axengine.InferenceSession(MODEL_PATHS["unet"])
54
+ self.vae = axengine.InferenceSession(MODEL_PATHS["vae"])
55
+ self.time_embeddings = np.load(MODEL_PATHS["time_embeddings"])
56
+ self.models_loaded = True
57
+ print("所有模型已成功加载到内存")
58
+ except Exception as e:
59
+ print(f"模型加载失败: {str(e)}")
60
+ raise
61
+
62
+ diffusion_models = DiffusionModels()
63
+
64
+ @asynccontextmanager
65
+ async def lifespan(app: FastAPI):
66
+ # 服务启动时加载模型
67
+ diffusion_models.load_models()
68
+ yield
69
+ # 服务关闭时清理资源
70
+ # (根据axengine的要求添加必要的清理逻辑)
71
+
72
+ app = FastAPI(lifespan=lifespan)
73
+
74
+ class GenerationRequest(BaseModel):
75
+ positive_prompt: str
76
+ negative_prompt: str = ""
77
+ num_inference_steps: int = 20
78
+ guidance_scale: float = 7.5
79
+ seed: int = None
80
+
81
+ @app.post("/generate")
82
+ async def generate_image(request: GenerationRequest):
83
+ try:
84
+ # 输入验证
85
+ if len(request.positive_prompt) > 1000:
86
+ raise ValueError("提示词过长")
87
+
88
+ # 执行推理流程
89
+ image = generate_diffusion_image(
90
+ positive_prompt=request.positive_prompt,
91
+ negative_prompt=request.negative_prompt,
92
+ num_steps=request.num_inference_steps,
93
+ guidance_scale=request.guidance_scale,
94
+ seed=request.seed
95
+ )
96
+
97
+ # 转换图像为字节流
98
+ img_byte_arr = io.BytesIO()
99
+ image.save(img_byte_arr, format='PNG')
100
+
101
+ return Response(content=img_byte_arr.getvalue(), media_type="image/png")
102
+
103
+ except Exception as e:
104
+ error_id = str(uuid.uuid4())
105
+ print(f"Error [{error_id}]: {str(e)}")
106
+ raise HTTPException(
107
+ status_code=500,
108
+ detail=f"生成失败,错误ID:{error_id}"
109
+ )
110
+
111
+
112
+
113
+ def get_embeds(prompt, negative_prompt):
114
+ """获取正负提示词的嵌入(带形状验证)"""
115
+ try:
116
+ debug_log(f"开始处理提示词: {prompt[:50]}...")
117
+ start_time = time.time()
118
+
119
+
120
+ def process_prompt(prompt_text):
121
+ inputs = diffusion_models.tokenizer(
122
+ prompt_text,
123
+ padding="max_length",
124
+ max_length=77,
125
+ truncation=True,
126
+ return_tensors="pt"
127
+ )
128
+ debug_log(f"Tokenizer输出形状: {inputs.input_ids.shape}")
129
+
130
+ outputs = diffusion_models.text_encoder.run(None, {"input_ids": inputs.input_ids.numpy().astype(np.int32)})[0]
131
+ debug_log(f"文本编码器输出形状: {outputs.shape} | dtype: {outputs.dtype}")
132
+ return outputs
133
+
134
+ neg_start = time.time()
135
+ neg_embeds = process_prompt(negative_prompt)
136
+ pos_embeds = process_prompt(prompt)
137
+ debug_log(f"文本编码完成 | 耗时: {(time.time()-start_time):.2f}s")
138
+
139
+ # 验证形状
140
+ if neg_embeds.shape != (1, 77, 768) or pos_embeds.shape != (1, 77, 768):
141
+ raise ValueError(f"嵌入形状异常: 负面{neg_embeds.shape}, 正面{pos_embeds.shape}")
142
+
143
+ return neg_embeds, pos_embeds
144
+ except Exception as e:
145
+ print(f"获取嵌入失败: {str(e)}")
146
+ traceback.print_exc()
147
+ exit(1)
148
+
149
+
150
+ def generate_diffusion_image(
151
+ positive_prompt: str,
152
+ negative_prompt: str,
153
+ num_steps: int = 20,
154
+ guidance_scale: float = 7.5,
155
+ seed: int = None
156
+ ) -> Image.Image:
157
+ """
158
+ 生成扩散图像的优化版本(保持输入形状不可变)
159
+
160
+ 参数:
161
+ positive_prompt (str): 正向提示词
162
+ negative_prompt (str): 负向提示词
163
+ num_steps (int): 推理步数 (默认20)
164
+ guidance_scale (float): 分类器自由引导系数 (默认7.5)
165
+ seed (int): 随机种子 (可选)
166
+
167
+ 返回:
168
+ PIL.Image.Image: 生成的图像
169
+
170
+ 异常:
171
+ ValueError: 输入参数无效时抛出
172
+ RuntimeError: 推理过程中出现错误时抛出
173
+ """
174
+ try:
175
+ # 参数验证
176
+ if not positive_prompt:
177
+ raise ValueError("正向提示词不能为空")
178
+ if guidance_scale < 1.0 or guidance_scale > 20.0:
179
+ raise ValueError("引导系数需在1.0-20.0之间")
180
+
181
+ debug_log("开始生成流程...")
182
+ start_time = time.time()
183
+
184
+ # =====================================================================
185
+ # 1. 初始化配置
186
+ # =====================================================================
187
+ seed = seed if seed is not None else int(time.time() * 1000) % 0xFFFFFFFF
188
+ torch.manual_seed(seed)
189
+ np.random.seed(seed)
190
+ debug_log(f"初始随机种子: {seed}")
191
+
192
+ # =====================================================================
193
+ # 2. 文本编码 (保持原有输入形状 [1, 77, 768])
194
+ # =====================================================================
195
+ embed_start = time.time()
196
+ neg_emb, pos_emb = get_embeds(
197
+ positive_prompt,
198
+ negative_prompt,
199
+ )
200
+ debug_log(f"文本编码完成 | 耗时: {time.time()-embed_start:.2f}s")
201
+
202
+ # =====================================================================
203
+ # 3. 初始化潜在变量 (固定形状 [1, 4, 60, 40])
204
+ # =====================================================================
205
+ scheduler = DPMSolverMultistepScheduler(
206
+ num_train_timesteps=1000,
207
+ beta_start=0.00085,
208
+ beta_end=0.012,
209
+ beta_schedule="scaled_linear",
210
+ algorithm_type="dpmsolver++",
211
+ use_karras_sigmas=True
212
+ )
213
+ scheduler.set_timesteps(num_steps)
214
+
215
+ latents_shape = (1, 4, 60, 40)
216
+ latent = torch.randn(latents_shape, generator=torch.Generator().manual_seed(seed))
217
+ latent = latent * scheduler.init_noise_sigma
218
+ latent = latent.numpy().astype(np.float32)
219
+ debug_log(f"潜在变量初始化 | 形状: {latent.shape} sigma:{scheduler.init_noise_sigma:.3f}")
220
+
221
+ # =====================================================================
222
+ # 4. 准备时间嵌入 (预加载数据截取)
223
+ # =====================================================================
224
+ if len(diffusion_models.time_embeddings) < num_steps:
225
+ raise ValueError(f"时间嵌入不足: 需要{num_steps}步 当前加载{len(diffusion_models.time_embeddings)}步")
226
+ time_steps = diffusion_models.time_embeddings[:num_steps]
227
+
228
+ # =====================================================================
229
+ # 5. 采样主循环 (保持输入形状不可变)
230
+ # =====================================================================
231
+ debug_log("开始采样循环...")
232
+ for step_idx, timestep in enumerate(scheduler.timesteps.numpy().astype(np.int64)):
233
+ step_start = time.time()
234
+
235
+ # 准备时间嵌入 (形状 [1, 1])
236
+ time_emb = np.expand_dims(time_steps[step_idx], axis=0)
237
+
238
+ # -----------------------------------------
239
+ # UNET双推理流程 (强制形状匹配)
240
+ # -----------------------------------------
241
+ # 负面提示推理
242
+ noise_pred_neg = diffusion_models.unet.run(None, {
243
+ "sample": latent,
244
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
245
+ "encoder_hidden_states": neg_emb
246
+ })[0]
247
+
248
+ # 正面提示推理
249
+ noise_pred_pos = diffusion_models.unet.run(None, {
250
+ "sample": latent,
251
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
252
+ "encoder_hidden_states": pos_emb
253
+ })[0]
254
+
255
+ # CFG融合 (数值稳定性优化)
256
+ noise_pred = noise_pred_neg + guidance_scale * (noise_pred_pos - noise_pred_neg)
257
+
258
+
259
+ # 转换为Tensor
260
+ latent_tensor = torch.from_numpy(latent)
261
+ noise_pred_tensor = torch.from_numpy(noise_pred)
262
+
263
+ # 调度器更新
264
+ debug_log("更新潜在变量...")
265
+ scheduler_start = time.time()
266
+ latent_tensor = scheduler.step(
267
+ model_output=noise_pred_tensor,
268
+ timestep=timestep,
269
+ sample=latent_tensor
270
+ ).prev_sample
271
+ debug_log(f"调度器更新完成 | 耗时: {(time.time()-scheduler_start):.2f}s")
272
+
273
+ # 转换回numpy
274
+ latent = latent_tensor.numpy().astype(np.float32)
275
+ debug_log(f"更新后潜在变量范围: [{latent.min():.3f}, {latent.max():.3f}]")
276
+
277
+ debug_log(f"步骤 {step_idx+1}/{num_steps} | 耗时: {time.time()-step_start:.2f}s")
278
+
279
+ # =====================================================================
280
+ # 6. VAE解码 (强制输出形状为768x512)
281
+ # =====================================================================
282
+ debug_log("开始VAE解码...")
283
+ vae_start = time.time()
284
+ latent = latent / 0.18215
285
+ image = diffusion_models.vae.run(None, {"latent": latent})[0]
286
+
287
+ # 转换为PIL图像 (优化内存拷贝)
288
+ image = np.transpose(image.squeeze(), (1, 2, 0))
289
+ image = np.clip((image / 2 + 0.5) * 255, 0, 255).astype(np.uint8)
290
+ pil_image = Image.fromarray(image[..., :3]) # 移除alpha通道
291
+ pil_image.save("./api.png")
292
+ debug_log(f"总耗时: {time.time()-start_time:.2f}s")
293
+ return pil_image
294
+
295
+ except Exception as e:
296
+ error_msg = f"生成失败: {str(e)}"
297
+ debug_log(error_msg)
298
+ traceback.print_exc()
299
+ raise RuntimeError(error_msg)
300
+
301
+
axengine-0.1.3-py3-none-any.whl ADDED
Binary file (19 kB). View file
 
client/app.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_file, send_from_directory
2
+ import os
3
+ import requests
4
+ from PIL import Image
5
+ import io
6
+
7
+ def generate_image(api_url, positive_prompt, negative_prompt=""):
8
+ payload = {
9
+ "positive_prompt": positive_prompt,
10
+ "negative_prompt": negative_prompt,
11
+ }
12
+
13
+ try:
14
+ response = requests.post(
15
+ f"{api_url}/generate",
16
+ json=payload,
17
+ timeout=30
18
+ )
19
+
20
+ if response.status_code == 200:
21
+ return Image.open(io.BytesIO(response.content))
22
+ else:
23
+ error_info = response.json().get("detail", "Unknown error")
24
+ print(f"生成失败 ({response.status_code}): {error_info}")
25
+
26
+ except Exception as e:
27
+ print(f"API调用异常: {str(e)}")
28
+
29
+
30
+ app = Flask(__name__)
31
+
32
+ # Serve static files from the current directory
33
+ @app.route('/<path:filename>')
34
+ def serve_static(filename):
35
+ return send_from_directory('.', filename)
36
+
37
+ @app.route('/')
38
+ def index():
39
+ return send_file('index.html')
40
+
41
+ @app.route('/generate', methods=['POST'])
42
+ def generate():
43
+ data = request.json
44
+ positive_prompt = ", ".join(data['terms'])
45
+
46
+ # Call image generation
47
+ image = generate_image(
48
+ "http://192.168.20.126:7888",
49
+ positive_prompt=positive_prompt,
50
+ negative_prompt="open cloth,pornographic,violence,wearing less,signature, soft, blurry, drawing, sketch, poor quality, ugly, text, type, word, logo, pixelated, low resolution, saturated, high contrast, oversharpened"
51
+ )
52
+
53
+ if image:
54
+ image_path = "generated_image.png"
55
+ image.save(image_path)
56
+ return send_file(image_path, mimetype='image/png')
57
+ else:
58
+ return jsonify({"error": "Image generation failed"}), 500
59
+
60
+ if __name__ == '__main__':
61
+ app.run(port=5000, debug=True)
client/index.html ADDED
@@ -0,0 +1,832 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>M5Stack LLM8850 文生图展示</title>
8
+ <style>
9
+ :root {
10
+ --primary-color: #3498db;
11
+ --selected-color: #e74c3c;
12
+ --success-color: #27ae60;
13
+ --warning-color: #f39c12;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
18
+ margin: 0;
19
+ padding: 20px;
20
+ background: #f0f3f5;
21
+ }
22
+
23
+ .container {
24
+ max-width: 100%;
25
+ margin: 0 auto;
26
+ background: white;
27
+ border-radius: 12px;
28
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
29
+ padding: 2rem;
30
+ position: relative;
31
+ }
32
+
33
+ /* 公司图标 */
34
+ .company-logo {
35
+ position: absolute;
36
+ top: 20px;
37
+ right: 20px;
38
+ width: 80px;
39
+ height: auto;
40
+ }
41
+
42
+ h1 {
43
+ text-align: center;
44
+ color: #2c3e50;
45
+ margin-bottom: 2rem;
46
+ font-weight: 600;
47
+ margin-right: 100px;
48
+ /* 为图标留出空间 */
49
+ }
50
+
51
+ /* 选中词条区域样式 */
52
+ #selected-terms-box {
53
+ position: sticky;
54
+ top: 0;
55
+ background: rgba(255, 255, 255, 0.95);
56
+ backdrop-filter: blur(5px);
57
+ z-index: 10;
58
+ padding: 1rem;
59
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
60
+ margin-bottom: 1.5rem;
61
+ border-radius: 8px;
62
+ }
63
+
64
+ .selected-terms-label {
65
+ font-weight: 500;
66
+ color: #2c3e50;
67
+ margin-bottom: 0.5rem;
68
+ font-size: 0.9rem;
69
+ }
70
+
71
+ .selected-term {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ padding: 0.4rem 0.8rem;
75
+ background: var(--selected-color);
76
+ color: white;
77
+ border-radius: 20px;
78
+ margin: 0.3rem;
79
+ font-size: 0.9em;
80
+ animation: popIn 0.2s ease;
81
+ cursor: pointer;
82
+ transition: all 0.2s ease;
83
+ }
84
+
85
+ .selected-term:hover {
86
+ background: #c0392b;
87
+ transform: scale(1.05);
88
+ }
89
+
90
+ .controls {
91
+ display: inline-flex;
92
+ gap: 0.5rem;
93
+ margin-left: 1rem;
94
+ vertical-align: middle;
95
+ }
96
+
97
+ .btn {
98
+ padding: 0.6rem 1.2rem;
99
+ border: none;
100
+ border-radius: 20px;
101
+ font-size: 0.9rem;
102
+ cursor: pointer;
103
+ transition: all 0.2s ease;
104
+ font-weight: 500;
105
+ }
106
+
107
+ #generate-btn {
108
+ background: var(--primary-color);
109
+ color: white;
110
+ padding: 1rem 2rem;
111
+ /* 放大生成按钮 */
112
+ font-size: 1.1rem;
113
+ font-weight: 600;
114
+ }
115
+
116
+ #random-btn {
117
+ background: var(--success-color);
118
+ color: white;
119
+ }
120
+
121
+ #clear-terms-btn {
122
+ background: var(--warning-color);
123
+ color: white;
124
+ }
125
+
126
+ #clear-images-btn {
127
+ background: #95a5a6;
128
+ color: white;
129
+ }
130
+
131
+ .btn:hover {
132
+ transform: translateY(-2px);
133
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
134
+ }
135
+
136
+ .btn:disabled {
137
+ background: #bdc3c7;
138
+ cursor: not-allowed;
139
+ transform: none;
140
+ box-shadow: none;
141
+ }
142
+
143
+ @keyframes popIn {
144
+ from {
145
+ transform: scale(0.8);
146
+ opacity: 0;
147
+ }
148
+
149
+ to {
150
+ transform: scale(1);
151
+ opacity: 1;
152
+ }
153
+ }
154
+
155
+ /* 进度条样式(非弹出式) */
156
+ .progress-container {
157
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
158
+ padding: 1rem;
159
+ border-radius: 8px;
160
+ margin-bottom: 1rem;
161
+ color: white;
162
+ display: none;
163
+ animation: slideDown 0.3s ease;
164
+ }
165
+
166
+ .progress-container.active {
167
+ display: block;
168
+ }
169
+
170
+ .progress-bar {
171
+ width: 100%;
172
+ height: 6px;
173
+ background: rgba(255, 255, 255, 0.3);
174
+ border-radius: 3px;
175
+ overflow: hidden;
176
+ margin: 0.5rem 0;
177
+ }
178
+
179
+ .progress-fill {
180
+ height: 100%;
181
+ background: linear-gradient(90deg, #fff, #f39c12);
182
+ width: 0%;
183
+ transition: width 0.3s ease;
184
+ border-radius: 3px;
185
+ }
186
+
187
+ .progress-info {
188
+ display: flex;
189
+ justify-content: space-between;
190
+ align-items: center;
191
+ font-size: 0.9rem;
192
+ }
193
+
194
+ .progress-step {
195
+ opacity: 0.9;
196
+ }
197
+
198
+ .fun-fact {
199
+ background: rgba(255, 255, 255, 0.1);
200
+ padding: 0.5rem;
201
+ border-radius: 4px;
202
+ margin-top: 0.5rem;
203
+ font-style: italic;
204
+ font-size: 0.85rem;
205
+ animation: fadeIn 0.5s ease;
206
+ }
207
+
208
+ @keyframes slideDown {
209
+ from {
210
+ opacity: 0;
211
+ transform: translateY(-20px);
212
+ }
213
+
214
+ to {
215
+ opacity: 1;
216
+ transform: translateY(0);
217
+ }
218
+ }
219
+
220
+ @keyframes fadeIn {
221
+ from {
222
+ opacity: 0;
223
+ transform: translateY(10px);
224
+ }
225
+
226
+ to {
227
+ opacity: 1;
228
+ transform: translateY(0);
229
+ }
230
+ }
231
+
232
+ /* 词条分类样式 */
233
+ #term-categories {
234
+ display: grid;
235
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
236
+ gap: 1.5rem;
237
+ }
238
+
239
+ .category {
240
+ background: #ffffff;
241
+ border-radius: 8px;
242
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
243
+ overflow: hidden;
244
+ }
245
+
246
+ .category-header {
247
+ padding: 1rem;
248
+ background: var(--primary-color);
249
+ color: white;
250
+ font-weight: 500;
251
+ position: sticky;
252
+ top: 0;
253
+ z-index: 1;
254
+ }
255
+
256
+ .scroll-container {
257
+ max-height: 240px;
258
+ overflow-y: hidden;
259
+ padding: 1rem;
260
+ position: relative;
261
+ }
262
+
263
+ .term-item {
264
+ padding: 0.8rem 1.2rem;
265
+ margin: 0.5rem 0;
266
+ border-radius: 6px;
267
+ background: #f8f9fa;
268
+ cursor: pointer;
269
+ transition: all 0.2s ease;
270
+ position: relative;
271
+ overflow: hidden;
272
+ display: flex;
273
+ align-items: center;
274
+ min-height: 48px;
275
+ }
276
+
277
+ .term-content {
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: 0.2rem;
281
+ }
282
+
283
+ .chinese {
284
+ font-weight: 500;
285
+ color: #2c3e50;
286
+ }
287
+
288
+ .term {
289
+ font-size: 0.85rem;
290
+ color: #7f8c8d;
291
+ font-style: italic;
292
+ }
293
+
294
+ .term-item.selected {
295
+ background: var(--primary-color);
296
+ color: white;
297
+ }
298
+
299
+ .term-item.selected .term {
300
+ color: rgba(255, 255, 255, 0.8);
301
+ }
302
+
303
+ .term-item:hover {
304
+ transform: translateX(5px);
305
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
306
+ }
307
+
308
+ /* 布局调整 - 占满屏幕 */
309
+ .main-content {
310
+ display: grid;
311
+ grid-template-columns: 1fr 500px;
312
+ gap: 2rem;
313
+ min-height: 70vh;
314
+ }
315
+
316
+ .left-column {
317
+ display: grid;
318
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
319
+ gap: 1.2rem;
320
+ align-content: start;
321
+ }
322
+
323
+ .right-column {
324
+ background: #f8f9fa;
325
+ border-radius: 8px;
326
+ padding: 1rem;
327
+ display: flex;
328
+ flex-direction: column;
329
+ }
330
+
331
+ .images-header {
332
+ text-align: center;
333
+ color: #2c3e50;
334
+ margin-bottom: 1rem;
335
+ font-size: 1.1rem;
336
+ font-weight: 500;
337
+ flex-shrink: 0;
338
+ }
339
+
340
+ /* 图片容器改为两列 */
341
+ #images-container {
342
+ display: grid;
343
+ grid-template-columns: 1fr 1fr;
344
+ gap: 1rem;
345
+ flex: 1;
346
+ }
347
+
348
+ .image-item {
349
+ background: white;
350
+ border-radius: 8px;
351
+ padding: 0.5rem;
352
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
353
+ animation: zoomIn 0.3s ease;
354
+ align-self: start;
355
+ }
356
+
357
+ .image-item img {
358
+ width: 100%;
359
+ height: auto;
360
+ border-radius: 6px;
361
+ display: block;
362
+ }
363
+
364
+ .image-terms {
365
+ font-size: 0.75rem;
366
+ color: #7f8c8d;
367
+ margin-top: 0.5rem;
368
+ padding: 0.5rem;
369
+ background: #ecf0f1;
370
+ border-radius: 4px;
371
+ word-wrap: break-word;
372
+ line-height: 1.3;
373
+ }
374
+
375
+ .empty-state {
376
+ grid-column: 1 / -1;
377
+ text-align: center;
378
+ color: #7f8c8d;
379
+ padding: 2rem;
380
+ font-style: italic;
381
+ }
382
+
383
+ @keyframes zoomIn {
384
+ from {
385
+ opacity: 0;
386
+ transform: scale(0.9);
387
+ }
388
+
389
+ to {
390
+ opacity: 1;
391
+ transform: scale(1);
392
+ }
393
+ }
394
+
395
+ /* 响应式设计 */
396
+ @media (max-width: 1400px) {
397
+ .main-content {
398
+ grid-template-columns: 1fr 450px;
399
+ }
400
+ }
401
+
402
+ @media (max-width: 1200px) {
403
+ .main-content {
404
+ grid-template-columns: 1fr;
405
+ }
406
+ }
407
+
408
+ @media (max-width: 768px) {
409
+ .container {
410
+ padding: 1rem;
411
+ }
412
+
413
+ .company-logo {
414
+ width: 60px;
415
+ top: 10px;
416
+ right: 10px;
417
+ }
418
+
419
+ h1 {
420
+ margin-right: 70px;
421
+ font-size: 1.5rem;
422
+ }
423
+
424
+ #term-categories {
425
+ grid-template-columns: 1fr;
426
+ }
427
+
428
+ #images-container {
429
+ grid-template-columns: 1fr;
430
+ }
431
+
432
+ .controls {
433
+ flex-direction: column;
434
+ gap: 0.5rem;
435
+ margin-left: 0;
436
+ margin-top: 1rem;
437
+ }
438
+
439
+ .btn {
440
+ padding: 0.8rem 1.5rem;
441
+ }
442
+
443
+ #generate-btn {
444
+ padding: 1rem 1.5rem;
445
+ }
446
+ }
447
+
448
+ /* 占满屏幕的调整 */
449
+ @media (min-width: 1600px) {
450
+ .container {
451
+ max-width: 95%;
452
+ }
453
+
454
+ .main-content {
455
+ grid-template-columns: 1fr 600px;
456
+ }
457
+
458
+ .left-column {
459
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
460
+ }
461
+ }
462
+ </style>
463
+ </head>
464
+
465
+ <body>
466
+ <div class="container">
467
+ <!-- 公司图标 -->
468
+ <img src="https://docs.m5stack.com/assets/m5logo2022.svg" alt="M5Stack Logo" class="company-logo">
469
+
470
+ <h1>M5Stack AI Pyrmind AX8850 文生图展示</h1>
471
+
472
+ <div id="selected-terms-box">
473
+ <div class="selected-terms-label">已选择的提示词 Selected Prompts:</div>
474
+ <div id="selected-terms-list"></div>
475
+ <div class="controls">
476
+ <button id="generate-btn" class="btn">立即生成 Generate Now</button>
477
+ <button id="random-btn" class="btn">随机描述 Random Terms</button>
478
+ <button id="clear-terms-btn" class="btn">清除提示词 Clear Terms</button>
479
+ <button id="clear-images-btn" class="btn">清除图片 Clear Images</button>
480
+ </div>
481
+ </div>
482
+
483
+ <!-- 非弹出式进度条 -->
484
+ <div class="progress-container" id="progress-container">
485
+ <div class="progress-info">
486
+ <span>AI 正在创作中... AI is creating...</span>
487
+ <span id="progress-percent">0%</span>
488
+ </div>
489
+ <div class="progress-bar">
490
+ <div class="progress-fill" id="progress-fill"></div>
491
+ </div>
492
+ <div class="progress-step" id="progress-step">初始化中... Initializing...</div>
493
+ <div class="fun-fact" id="fun-fact"></div>
494
+ </div>
495
+
496
+ <div class="main-content">
497
+ <div class="left-column">
498
+ <div id="term-categories"></div>
499
+ </div>
500
+
501
+ <div class="right-column">
502
+ <div class="images-header">生成历史 Generation History</div>
503
+ <div id="images-container">
504
+ <div class="empty-state">
505
+ 选择词条并点击生成按钮开始创作<br>
506
+ Select terms and click generate to start creating
507
+ </div>
508
+ </div>
509
+ </div>
510
+ </div>
511
+ </div>
512
+
513
+ <script>
514
+ let scrollControllers = new Map();
515
+ // 有趣的提示词汇
516
+ const funFacts = [
517
+ "正在分析你的创意想法... Analyzing your creative ideas...",
518
+ "AI 大脑正在思考最佳构图... AI brain thinking about optimal composition...",
519
+ "调色板准备中,寻找完美色彩... Preparing palette, finding perfect colors...",
520
+ "像素精灵们正在排队组合... Pixel sprites lining up for combination...",
521
+ "魔法正在将文字转化为视觉... Magic transforming text to visuals...",
522
+ "创意工厂全速运转中... Creative factory at full speed...",
523
+ "每个细节都在精心雕琢... Every detail carefully crafted...",
524
+ "光影大师正在调整明暗... Light master adjusting brightness...",
525
+ "笔刷正在画布上飞舞... Brushes dancing on canvas...",
526
+ "艺术灵感正在汇聚成形... Artistic inspiration taking shape...",
527
+ "创造力引擎火力全开... Creativity engine at full power...",
528
+ "美学算法正在优化细节... Aesthetic algorithm optimizing details...",
529
+ "视觉交响乐即将奏响... Visual symphony about to play...",
530
+ "想象力正在突破边界... Imagination breaking boundaries...",
531
+ "奇迹工坊正在施展魔法... Miracle workshop casting magic..."
532
+ ];
533
+
534
+ // UNet去噪步骤提示
535
+ const unetSteps = [
536
+ "预处理输入图层... Preprocessing input layers...",
537
+ "第1层卷积神经网络��理... Layer 1 CNN processing...",
538
+ "第2层特征提取中... Layer 2 feature extraction...",
539
+ "第3层语义理解... Layer 3 semantic understanding...",
540
+ "第4层细节优化... Layer 4 detail optimization...",
541
+ "第5层色彩调和... Layer 5 color harmony...",
542
+ "第6层纹理生成... Layer 6 texture generation...",
543
+ "第7层构图调整... Layer 7 composition adjustment...",
544
+ "第8层光影处理... Layer 8 lighting processing...",
545
+ "第9层细节增强... Layer 9 detail enhancement...",
546
+ "第10层质量检查... Layer 10 quality check...",
547
+ "第11层风格融合... Layer 11 style fusion...",
548
+ "第12层最终调色... Layer 12 final coloring...",
549
+ "第13层锐化处理... Layer 13 sharpening...",
550
+ "第14层噪声去除... Layer 14 noise removal...",
551
+ "第15层对比度优化... Layer 15 contrast optimization...",
552
+ "第16层饱和度调节... Layer 16 saturation adjustment...",
553
+ "第17层最终渲染... Layer 17 final rendering...",
554
+ "第18层质量验证... Layer 18 quality validation...",
555
+ "第19层输出准备... Layer 19 output preparation...",
556
+ "第20层完成处理... Layer 20 completion..."
557
+ ];
558
+
559
+ async function loadAndDisplayTerms() {
560
+ try {
561
+ const response = await fetch('./person.json');
562
+ const data = await response.json();
563
+ const proprietaryTerms = data.prompt_terms.filter(term => term.type === "专用");
564
+ const categories = proprietaryTerms.reduce((acc, term) => {
565
+ const subtype = term.subtype || "通用 General";
566
+ acc[subtype] = acc[subtype] || [];
567
+ acc[subtype].push(term);
568
+ return acc;
569
+ }, {});
570
+ const container = document.getElementById('term-categories');
571
+ Object.entries(categories).forEach(([subtype, terms]) => {
572
+ const category = document.createElement('div');
573
+ category.className = 'category';
574
+ const header = document.createElement('div');
575
+ header.className = 'category-header';
576
+ header.textContent = subtype;
577
+ const scrollContainer = document.createElement('div');
578
+ scrollContainer.className = 'scroll-container';
579
+ terms.forEach(term => {
580
+ const item = document.createElement('div');
581
+ item.className = 'term-item';
582
+ item.dataset.term = term.term;
583
+ item.innerHTML = `
584
+ <div class="term-content">
585
+ <div class="chinese">${term.chinese}</div>
586
+ <div class="term">${term.term}</div>
587
+ </div>
588
+ `;
589
+ scrollContainer.appendChild(item);
590
+ });
591
+ category.append(header, scrollContainer);
592
+ container.appendChild(category);
593
+ if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
594
+ setupAutoScroll(scrollContainer);
595
+ }
596
+ });
597
+ } catch (error) {
598
+ console.error('数据加载失败 Data loading failed:', error);
599
+ }
600
+ }
601
+
602
+ function setupAutoScroll(container) {
603
+ let isPaused = false;
604
+ let scrollPos = 0;
605
+ const scrollSpeed = 0.5;
606
+ const scrollHeight = container.scrollHeight - container.clientHeight;
607
+ container.addEventListener('mouseenter', () => isPaused = true);
608
+ container.addEventListener('mouseleave', () => isPaused = false);
609
+ const scroll = () => {
610
+ if (!isPaused && scrollHeight > 0) {
611
+ scrollPos = (scrollPos + scrollSpeed) % scrollHeight;
612
+ const easedPos = scrollPos < scrollHeight / 2 ? scrollPos : scrollHeight - scrollPos;
613
+ container.scrollTop = easedPos;
614
+ }
615
+ requestAnimationFrame(scroll);
616
+ };
617
+ scroll();
618
+ }
619
+
620
+ function updateSelections() {
621
+ const selectedItems = Array.from(document.querySelectorAll('.term-item.selected'));
622
+ const container = document.getElementById('selected-terms-list');
623
+
624
+ container.innerHTML = selectedItems.map(item => {
625
+ const chinese = item.querySelector('.chinese').textContent;
626
+ const english = item.querySelector('.term').textContent;
627
+ return `<span class="selected-term" data-term="${english}">${chinese} ${english}</span>`;
628
+ }).join('');
629
+ }
630
+
631
+ function showProgress() {
632
+ const container = document.getElementById('progress-container');
633
+ const progressFill = document.getElementById('progress-fill');
634
+ const progressStep = document.getElementById('progress-step');
635
+ const progressPercent = document.getElementById('progress-percent');
636
+ const funFact = document.getElementById('fun-fact');
637
+ container.classList.add('active');
638
+ let currentStep = 0;
639
+ const totalSteps = 20;
640
+ const stepDuration = 240; //进度条刷新时间
641
+ return new Promise((resolve) => {
642
+ const interval = setInterval(() => {
643
+ currentStep++;
644
+ const progress = (currentStep / totalSteps) * 100;
645
+ progressFill.style.width = progress + '%';
646
+ progressPercent.textContent = Math.round(progress) + '%';
647
+ progressStep.textContent = unetSteps[currentStep - 1] || '处理中... Processing...';
648
+ if (currentStep % 3 === 0) {
649
+ const randomFact = funFacts[Math.floor(Math.random() * funFacts.length)];
650
+ funFact.textContent = randomFact;
651
+ }
652
+ if (currentStep >= totalSteps) {
653
+ clearInterval(interval);
654
+ progressStep.textContent = '即将完成... Almost done...';
655
+ setTimeout(() => {
656
+ container.classList.remove('active');
657
+ resolve();
658
+ }, 500);
659
+ }
660
+ }, stepDuration);
661
+ });
662
+ }
663
+
664
+ function addImageToHistory(selectedTerms) {
665
+ const imagesContainer = document.getElementById('images-container');
666
+ // 清空初始提示
667
+ const emptyState = imagesContainer.querySelector('.empty-state');
668
+ if (emptyState) {
669
+ emptyState.remove();
670
+ }
671
+ const imgContainer = document.createElement('div');
672
+ imgContainer.className = 'image-item';
673
+ const img = document.createElement('img');
674
+ img.src = 'generated_image.png?' + new Date().getTime();
675
+ img.alt = 'Generated Image';
676
+ const termsDiv = document.createElement('div');
677
+ termsDiv.className = 'image-terms';
678
+ termsDiv.textContent = '关键词 Keywords: ' + selectedTerms.join(', ');
679
+ imgContainer.appendChild(img);
680
+ imgContainer.appendChild(termsDiv);
681
+ // 添加到开头
682
+ imagesContainer.prepend(imgContainer);
683
+ // 限制历史记录数量
684
+ while (imagesContainer.children.length > 20) {
685
+ imagesContainer.removeChild(imagesContainer.lastChild);
686
+ }
687
+ }
688
+
689
+ function clearAllTerms() {
690
+ // 清除所有选中状态
691
+ document.querySelectorAll('.term-item.selected').forEach(item => {
692
+ item.classList.remove('selected');
693
+ });
694
+ updateSelections();
695
+ }
696
+
697
+ function clearAllImages() {
698
+ const imagesContainer = document.getElementById('images-container');
699
+ imagesContainer.innerHTML = '<div class="empty-state">选择词条并点击生成按钮开始创作<br>Select terms and click generate to start creating</div>';
700
+ }
701
+
702
+ // 随机选择每个类别中的一个提示词
703
+ function selectRandomTerms() {
704
+ // 先清除所有已选择的词条
705
+ clearAllTerms();
706
+
707
+ // 获取所有类别
708
+ const categories = document.querySelectorAll('.category');
709
+ const randomTerms = [];
710
+
711
+ categories.forEach(category => {
712
+ const termItems = category.querySelectorAll('.term-item');
713
+ if (termItems.length > 0) {
714
+ // 从每个类别中随机选择一个
715
+ const randomIndex = Math.floor(Math.random() * termItems.length);
716
+ const selectedItem = termItems[randomIndex];
717
+ selectedItem.classList.add('selected');
718
+ randomTerms.push({
719
+ chinese: selectedItem.querySelector('.chinese').textContent,
720
+ english: selectedItem.querySelector('.term').textContent
721
+ });
722
+ }
723
+ });
724
+
725
+ // 更新选中的词条显示
726
+ updateSelections();
727
+
728
+ // 可选:显示一个提示告诉用户选择了哪些词条
729
+ if (randomTerms.length > 0) {
730
+ console.log('随机选择的词条:', randomTerms);
731
+ // 可以添加一个简短的提示
732
+ const notification = document.createElement('div');
733
+ notification.style.cssText = `
734
+ position: fixed;
735
+ top: 20px;
736
+ left: 50%;
737
+ transform: translateX(-50%);
738
+ background: var(--success-color);
739
+ color: white;
740
+ padding: 0.8rem 1.5rem;
741
+ border-radius: 20px;
742
+ z-index: 1000;
743
+ animation: slideDown 0.3s ease;
744
+ `;
745
+ notification.textContent = `已随机选择 ${randomTerms.length} 个词条 Randomly selected ${randomTerms.length} terms`;
746
+ document.body.appendChild(notification);
747
+
748
+ // 3秒后移除提示
749
+ setTimeout(() => {
750
+ notification.remove();
751
+ }, 3000);
752
+ }
753
+ }
754
+
755
+ // 事件监听
756
+ document.addEventListener('click', (e) => {
757
+ // 点击词条选择/取消选择
758
+ if (e.target.closest('.term-item')) {
759
+ const item = e.target.closest('.term-item');
760
+ item.classList.toggle('selected');
761
+ updateSelections();
762
+ }
763
+ // 点击已选择的词条气泡取消选择
764
+ if (e.target.closest('.selected-term')) {
765
+ const term = e.target.closest('.selected-term').dataset.term;
766
+ const termItem = document.querySelector(`.term-item[data-term="${term}"]`);
767
+ if (termItem) {
768
+ termItem.classList.remove('selected');
769
+ updateSelections();
770
+ }
771
+ }
772
+ });
773
+
774
+ window.addEventListener('load', () => {
775
+ loadAndDisplayTerms();
776
+ const generateBtn = document.getElementById('generate-btn');
777
+ const randomBtn = document.getElementById('random-btn');
778
+ const clearTermsBtn = document.getElementById('clear-terms-btn');
779
+ const clearImagesBtn = document.getElementById('clear-images-btn');
780
+
781
+ // 生成按钮
782
+ generateBtn.addEventListener('click', async () => {
783
+ const selectedTerms = Array.from(document.querySelectorAll('.term-item.selected'))
784
+ .map(item => item.dataset.term);
785
+ if (selectedTerms.length === 0) {
786
+ alert('请至少选择一个词条 Please select at least one term');
787
+ return;
788
+ }
789
+ generateBtn.disabled = true;
790
+ const progressPromise = showProgress();
791
+ try {
792
+ const [response] = await Promise.all([
793
+ fetch('/generate', {
794
+ method: 'POST',
795
+ headers: {
796
+ 'Content-Type': 'application/json'
797
+ },
798
+ body: JSON.stringify({ terms: selectedTerms })
799
+ }),
800
+ progressPromise
801
+ ]);
802
+ if (response.ok) {
803
+ addImageToHistory(selectedTerms);
804
+ } else {
805
+ const error = await response.json();
806
+ alert(`生成失败 Generation failed: ${error.error}`);
807
+ }
808
+ } catch (error) {
809
+ console.error('生成请求失败 Generation request failed:', error);
810
+ alert('生成请求失败,请检查网络连接 Generation request failed, please check network connection');
811
+ } finally {
812
+ generateBtn.disabled = false;
813
+ }
814
+ });
815
+ randomBtn.addEventListener('click', () => {
816
+ selectRandomTerms();
817
+ });
818
+
819
+ // 清除提示词按钮
820
+ clearTermsBtn.addEventListener('click', clearAllTerms);
821
+
822
+ // 清除图片按钮
823
+ clearImagesBtn.addEventListener('click', () => {
824
+ if (confirm('确定要清除所有生成的图片吗? Are you sure you want to clear all generated images?')) {
825
+ clearAllImages();
826
+ }
827
+ });
828
+ });
829
+ </script>
830
+ </body>
831
+
832
+ </html>
client/person.json ADDED
@@ -0,0 +1,1038 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "prompt_terms": [
3
+ {
4
+ "term": "masterpiece",
5
+ "type": "通用",
6
+ "chinese": "杰作级别"
7
+ },
8
+ {
9
+ "term": "fox tail",
10
+ "type": "专用",
11
+ "subtype": "装饰 Accessory",
12
+ "chinese": "狐狸尾巴"
13
+ },
14
+ {
15
+ "term": "crystal tiara",
16
+ "type": "专用",
17
+ "subtype": "装饰 Accessory",
18
+ "chinese": "水晶王冠"
19
+ },
20
+ {
21
+ "term": "feather hairpin",
22
+ "type": "专用",
23
+ "subtype": "装饰 Accessory",
24
+ "chinese": "羽毛发夹"
25
+ },
26
+ {
27
+ "term": "butterfly wings",
28
+ "type": "专用",
29
+ "subtype": "装饰 Accessory",
30
+ "chinese": "蝴蝶翅膀"
31
+ },
32
+ {
33
+ "term": "star-shaped earrings",
34
+ "type": "专用",
35
+ "subtype": "装饰 Accessory",
36
+ "chinese": "星星耳饰"
37
+ },
38
+ {
39
+ "term": "ribbon choker",
40
+ "type": "专用",
41
+ "subtype": "装饰 Accessory",
42
+ "chinese": "缎带项圈"
43
+ },
44
+ {
45
+ "term": "flower crown",
46
+ "type": "专用",
47
+ "subtype": "装饰 Accessory",
48
+ "chinese": "花环"
49
+ },
50
+ {
51
+ "term": "glowing bracelets",
52
+ "type": "专用",
53
+ "subtype": "装饰 Accessory",
54
+ "chinese": "发光手镯"
55
+ },
56
+ {
57
+ "term": "goggles on head",
58
+ "type": "专用",
59
+ "subtype": "装饰 Accessory",
60
+ "chinese": "头戴护目镜"
61
+ },
62
+ {
63
+ "term": "steampunk attire",
64
+ "type": "专用",
65
+ "subtype": "衣服 Clothing",
66
+ "chinese": "蒸汽朋克服饰"
67
+ },
68
+ {
69
+ "term": "elven robe",
70
+ "type": "专用",
71
+ "subtype": "衣服 Clothing",
72
+ "chinese": "精灵长袍"
73
+ },
74
+ {
75
+ "term": "celestial dress",
76
+ "type": "专用",
77
+ "subtype": "衣服 Clothing",
78
+ "chinese": "星空连衣裙"
79
+ },
80
+ {
81
+ "term": "samurai armor",
82
+ "type": "专用",
83
+ "subtype": "衣服 Clothing",
84
+ "chinese": "武士铠甲"
85
+ },
86
+ {
87
+ "term": "futuristic bodysuit",
88
+ "type": "专用",
89
+ "subtype": "衣服 Clothing",
90
+ "chinese": "未来紧身服"
91
+ },
92
+ {
93
+ "term": "historical royal gown",
94
+ "type": "专用",
95
+ "subtype": "衣服 Clothing",
96
+ "chinese": "历史宫廷礼服"
97
+ },
98
+ {
99
+ "term": "vintage detective coat",
100
+ "type": "专用",
101
+ "subtype": "衣服 Clothing",
102
+ "chinese": "复古侦探大衣"
103
+ },
104
+ {
105
+ "term": "wizard cloak",
106
+ "type": "专用",
107
+ "subtype": "衣服 Clothing",
108
+ "chinese": "巫师斗篷"
109
+ },
110
+ {
111
+ "term": "fairy tale costume",
112
+ "type": "专用",
113
+ "subtype": "衣服 Clothing",
114
+ "chinese": "童话服装"
115
+ },
116
+ {
117
+ "term": "tilting head",
118
+ "type": "专用",
119
+ "subtype": "动作 Action",
120
+ "chinese": "歪头"
121
+ },
122
+ {
123
+ "term": "smiling gently",
124
+ "type": "专用",
125
+ "subtype": "动作 Action",
126
+ "chinese": "温柔微笑"
127
+ },
128
+ {
129
+ "term": "eyes closed",
130
+ "type": "专用",
131
+ "subtype": "动作 Action",
132
+ "chinese": "闭眼"
133
+ },
134
+ {
135
+ "term": "looking up",
136
+ "type": "专用",
137
+ "subtype": "动作 Action",
138
+ "chinese": "仰望"
139
+ },
140
+ {
141
+ "term": "looking down",
142
+ "type": "专用",
143
+ "subtype": "动作 Action",
144
+ "chinese": "俯视"
145
+ },
146
+ {
147
+ "term": "blushing",
148
+ "type": "专用",
149
+ "subtype": "动作 Action",
150
+ "chinese": "脸红"
151
+ },
152
+ {
153
+ "term": "resting chin on something",
154
+ "type": "专用",
155
+ "subtype": "动作 Action",
156
+ "chinese": "下巴倚靠"
157
+ },
158
+ {
159
+ "term": "hair flowing in wind",
160
+ "type": "专用",
161
+ "subtype": "动作 Action",
162
+ "chinese": "秀发随风飘扬"
163
+ },
164
+ {
165
+ "term": "leaning back",
166
+ "type": "专用",
167
+ "subtype": "动作 Action",
168
+ "chinese": "后仰"
169
+ },
170
+ {
171
+ "term": "shoulders slightly raised",
172
+ "type": "专用",
173
+ "subtype": "动作 Action",
174
+ "chinese": "微耸双肩"
175
+ },
176
+ {
177
+ "term": "playing an instrument",
178
+ "type": "专用",
179
+ "subtype": "动作 Action",
180
+ "chinese": "演奏乐器"
181
+ },
182
+ {
183
+ "term": "exploring surroundings",
184
+ "type": "专用",
185
+ "subtype": "动作 Action",
186
+ "chinese": "探索四周"
187
+ },
188
+ {
189
+ "term": "enchanted forest",
190
+ "type": "专用",
191
+ "subtype": "场景 Scene",
192
+ "chinese": "魔法森林"
193
+ },
194
+ {
195
+ "term": "crystal cave",
196
+ "type": "专用",
197
+ "subtype": "场景 Scene",
198
+ "chinese": "水晶洞穴"
199
+ },
200
+ {
201
+ "term": "ancient ruins",
202
+ "type": "专用",
203
+ "subtype": "场景 Scene",
204
+ "chinese": "远古遗迹"
205
+ },
206
+ {
207
+ "term": "starlit meadow",
208
+ "type": "专用",
209
+ "subtype": "场景 Scene",
210
+ "chinese": "星光草原"
211
+ },
212
+ {
213
+ "term": "underwater",
214
+ "type": "专用",
215
+ "subtype": "场景 Scene",
216
+ "chinese": "水下"
217
+ },
218
+ {
219
+ "term": "autumn grove",
220
+ "type": "专用",
221
+ "subtype": "场景 Scene",
222
+ "chinese": "秋日林地"
223
+ },
224
+ {
225
+ "term": "best quality",
226
+ "type": "通用",
227
+ "chinese": "最佳质量"
228
+ },
229
+ {
230
+ "term": "game cg",
231
+ "type": "通用",
232
+ "subtype": "风格 Style",
233
+ "chinese": "游戏CG风格"
234
+ },
235
+ {
236
+ "term": "1boy",
237
+ "type": "专用",
238
+ "subtype": "主题 Subject",
239
+ "chinese": "一个男孩"
240
+ },
241
+ {
242
+ "term": "looking at viewer",
243
+ "type": "专用",
244
+ "subtype": "动作 Action",
245
+ "chinese": "看向观众"
246
+ },
247
+ {
248
+ "term": "ligne claire",
249
+ "type": "通用",
250
+ "subtype": "风格 Style",
251
+ "chinese": "清晰线条风格"
252
+ },
253
+ {
254
+ "term": "grey hair",
255
+ "type": "专用",
256
+ "subtype": "头发 Hair",
257
+ "chinese": "灰色头发"
258
+ },
259
+ {
260
+ "term": "green eyes",
261
+ "type": "专用",
262
+ "subtype": "眼睛 Eyes",
263
+ "chinese": "绿色眼睛"
264
+ },
265
+ {
266
+ "term": "animal ears",
267
+ "type": "专用",
268
+ "subtype": "装饰 Accessory",
269
+ "chinese": "动物耳朵"
270
+ },
271
+ {
272
+ "term": "cat ears",
273
+ "type": "专用",
274
+ "subtype": "装饰 Accessory",
275
+ "chinese": "猫耳"
276
+ },
277
+ {
278
+ "term": "swashbuckler costume",
279
+ "type": "专用",
280
+ "subtype": "衣服 Clothing",
281
+ "chinese": "侠客服装"
282
+ },
283
+ {
284
+ "term": "night sky",
285
+ "type": "专用",
286
+ "subtype": "场景 Scene",
287
+ "chinese": "夜空"
288
+ },
289
+ {
290
+ "term": "1girl",
291
+ "type": "专用",
292
+ "subtype": "主题 Subject",
293
+ "chinese": "一个女孩"
294
+ },
295
+ {
296
+ "term": "fantasy style",
297
+ "type": "专用",
298
+ "subtype": "风格 Style",
299
+ "chinese": "奇幻风格"
300
+ },
301
+ {
302
+ "term": "official art",
303
+ "type": "专用",
304
+ "subtype": "风格 Style",
305
+ "chinese": "官方美术风格"
306
+ },
307
+ {
308
+ "term": "baroque elegance",
309
+ "type": "专用",
310
+ "subtype": "风格 Style",
311
+ "chinese": "巴洛克优雅风格"
312
+ },
313
+ {
314
+ "term": "neo-noir lighting",
315
+ "type": "专用",
316
+ "subtype": "风格 Style",
317
+ "chinese": "新黑色电影风格"
318
+ },
319
+ {
320
+ "term": "surreal dreamscape",
321
+ "type": "专用",
322
+ "subtype": "风格 Style",
323
+ "chinese": "超现实梦境风格"
324
+ },
325
+ {
326
+ "term": "gothic romance",
327
+ "type": "专用",
328
+ "subtype": "风格 Style",
329
+ "chinese": "哥特浪漫风格"
330
+ },
331
+ {
332
+ "term": "celestial fantasy",
333
+ "type": "专用",
334
+ "subtype": "风格 Style",
335
+ "chinese": "天体奇幻风格"
336
+ },
337
+ {
338
+ "term": "bioluminescent night",
339
+ "type": "专用",
340
+ "subtype": "风格 Style",
341
+ "chinese": "生物发光夜景风格"
342
+ },
343
+ {
344
+ "term": "arcane vintage",
345
+ "type": "专用",
346
+ "subtype": "风格 Style",
347
+ "chinese": "神秘复古风格"
348
+ },
349
+ {
350
+ "term": "storybook illustration",
351
+ "type": "专用",
352
+ "subtype": "风格 Style",
353
+ "chinese": "童话书插画风格"
354
+ },
355
+ {
356
+ "term": "ethereal watercolor",
357
+ "type": "专用",
358
+ "subtype": "风格 Style",
359
+ "chinese": "空灵水彩画风"
360
+ },
361
+ {
362
+ "term": "futuristic abstraction",
363
+ "type": "专用",
364
+ "subtype": "风格 Style",
365
+ "chinese": "未来抽象风格"
366
+ },
367
+ {
368
+ "term": "4k textures",
369
+ "type": "通用",
370
+ "subtype": "quality",
371
+ "chinese": "4K纹理"
372
+ },
373
+ {
374
+ "term": "black hair",
375
+ "type": "专用",
376
+ "subtype": "头发 Hair",
377
+ "chinese": "黑发"
378
+ },
379
+ {
380
+ "term": "detailed feathers",
381
+ "type": "专用",
382
+ "subtype": "装饰 Accessory",
383
+ "chinese": "精细羽毛"
384
+ },
385
+ {
386
+ "term": "aggressive pose",
387
+ "type": "专用",
388
+ "subtype": "动作 Action",
389
+ "chinese": "攻击性姿势"
390
+ },
391
+ {
392
+ "term": "midflight",
393
+ "type": "专用",
394
+ "subtype": "动作 Action",
395
+ "chinese": "飞行中"
396
+ },
397
+ {
398
+ "term": "glowing effects",
399
+ "type": "专用",
400
+ "subtype": "场景 Scene",
401
+ "chinese": "发光特效"
402
+ },
403
+ {
404
+ "term": "dark background",
405
+ "type": "专用",
406
+ "subtype": "场景 Scene",
407
+ "chinese": "暗色背景"
408
+ },
409
+ {
410
+ "term": "fire",
411
+ "type": "专用",
412
+ "subtype": "场景 Scene",
413
+ "chinese": "火焰"
414
+ },
415
+ {
416
+ "term": "dramatic lighting",
417
+ "type": "通用",
418
+ "subtype": "lighting",
419
+ "chinese": "戏剧性打光"
420
+ },
421
+ {
422
+ "term": "sharp focus",
423
+ "type": "通用",
424
+ "subtype": "quality",
425
+ "chinese": "锐利焦点"
426
+ },
427
+ {
428
+ "term": "epic scenery",
429
+ "type": "专用",
430
+ "subtype": "场景 Scene",
431
+ "chinese": "史诗级场景"
432
+ },
433
+ {
434
+ "term": "hdr",
435
+ "type": "通用",
436
+ "subtype": "quality",
437
+ "chinese": "高动态范围"
438
+ },
439
+ {
440
+ "term": "movie still",
441
+ "type": "通用",
442
+ "subtype": "风格 Style",
443
+ "chinese": "电影剧照风格"
444
+ },
445
+ {
446
+ "term": "depth of field",
447
+ "type": "通用",
448
+ "subtype": "photography",
449
+ "chinese": "景深效果"
450
+ },
451
+ {
452
+ "term": "anime coloring",
453
+ "type": "通用",
454
+ "subtype": "风格 Style",
455
+ "chinese": "动漫上色风格"
456
+ },
457
+ {
458
+ "term": "blonde hair",
459
+ "type": "专用",
460
+ "subtype": "头发 Hair",
461
+ "chinese": "金发"
462
+ },
463
+ {
464
+ "term": "yellow eyes",
465
+ "type": "专用",
466
+ "subtype": "眼睛 Eyes",
467
+ "chinese": "黄瞳"
468
+ },
469
+ {
470
+ "term": "multicolored hair",
471
+ "type": "专用",
472
+ "subtype": "头发 Hair",
473
+ "chinese": "多色头发"
474
+ },
475
+ {
476
+ "term": "two-tone hair",
477
+ "type": "专用",
478
+ "subtype": "头发 Hair",
479
+ "chinese": "双色渐变发"
480
+ },
481
+ {
482
+ "term": "jewelry",
483
+ "type": "专用",
484
+ "subtype": "装饰 Accessory",
485
+ "chinese": "珠宝饰品"
486
+ },
487
+ {
488
+ "term": "butler costume",
489
+ "type": "专用",
490
+ "subtype": "衣服 Clothing",
491
+ "chinese": "管家服饰"
492
+ },
493
+ {
494
+ "term": "world war 1",
495
+ "type": "专用",
496
+ "subtype": "场景 Scene",
497
+ "chinese": "一战背景"
498
+ },
499
+ {
500
+ "term": "High resolution",
501
+ "type": "通用",
502
+ "subtype": "quality",
503
+ "chinese": "高清分辨率"
504
+ },
505
+ {
506
+ "term": "photorealistic",
507
+ "type": "通用",
508
+ "subtype": "风格 Style",
509
+ "chinese": "照片级写实"
510
+ },
511
+ {
512
+ "term": "4k",
513
+ "type": "通用",
514
+ "subtype": "quality",
515
+ "chinese": "4K超清"
516
+ },
517
+ {
518
+ "term": "Masterpiece",
519
+ "type": "通用",
520
+ "chinese": "大师级作品"
521
+ },
522
+ {
523
+ "term": "extremely detailed",
524
+ "type": "通用",
525
+ "subtype": "quality",
526
+ "chinese": "极致细节"
527
+ },
528
+ {
529
+ "term": "professional photography",
530
+ "type": "通用",
531
+ "subtype": "风格 Style",
532
+ "chinese": "专业摄影质感"
533
+ },
534
+ {
535
+ "term": "sharp detail",
536
+ "type": "通用",
537
+ "subtype": "quality",
538
+ "chinese": "锐利细节"
539
+ },
540
+ {
541
+ "term": "grey eyes",
542
+ "type": "专用",
543
+ "subtype": "眼睛 Eyes",
544
+ "chinese": "灰眸"
545
+ },
546
+ {
547
+ "term": "earrings",
548
+ "type": "专用",
549
+ "subtype": "装饰 Accessory",
550
+ "chinese": "耳环饰品"
551
+ },
552
+ {
553
+ "term": "cloche hat",
554
+ "type": "专用",
555
+ "subtype": "装饰 Accessory",
556
+ "chinese": "钟形女帽"
557
+ },
558
+ {
559
+ "term": "steampunk",
560
+ "type": "专用",
561
+ "subtype": "风格 Style",
562
+ "chinese": "蒸汽朋克主题"
563
+ },
564
+ {
565
+ "term": "intricate details",
566
+ "type": "通用",
567
+ "subtype": "quality",
568
+ "chinese": "复杂细节"
569
+ },
570
+ {
571
+ "term": "unity 8k wallpaper",
572
+ "type": "通用",
573
+ "subtype": "风格 Style",
574
+ "chinese": "Unity引擎8K壁纸风格"
575
+ },
576
+ {
577
+ "term": "ultra detailed",
578
+ "type": "通用",
579
+ "subtype": "quality",
580
+ "chinese": "超精细细节"
581
+ },
582
+ {
583
+ "term": "beautiful and aesthetic",
584
+ "type": "通用",
585
+ "subtype": "风格 Style",
586
+ "chinese": "唯美艺术风格"
587
+ },
588
+ {
589
+ "term": "perfect lighting",
590
+ "type": "通用",
591
+ "subtype": "photography",
592
+ "chinese": "完美布光"
593
+ },
594
+ {
595
+ "term": "gradient coloured hair",
596
+ "type": "专用",
597
+ "subtype": "头发 Hair",
598
+ "chinese": "渐变色发型"
599
+ },
600
+ {
601
+ "term": "sfw",
602
+ "type": "通用",
603
+ "subtype": "safety",
604
+ "chinese": "安全内容过滤"
605
+ },
606
+ {
607
+ "term": "expressionless",
608
+ "type": "专用",
609
+ "subtype": "动作 Action",
610
+ "chinese": "无表情状态"
611
+ },
612
+ {
613
+ "term": "formal",
614
+ "type": "专用",
615
+ "subtype": "衣服 Clothing",
616
+ "chinese": "正式着装"
617
+ },
618
+ {
619
+ "term": "necktie",
620
+ "type": "专用",
621
+ "subtype": "装饰 Accessory",
622
+ "chinese": "领带"
623
+ },
624
+ {
625
+ "term": "dress shirt",
626
+ "type": "专用",
627
+ "subtype": "衣服 Clothing",
628
+ "chinese": "衬衫"
629
+ },
630
+ {
631
+ "term": "ray tracing",
632
+ "type": "通用",
633
+ "subtype": "photography",
634
+ "chinese": "光线追踪技术"
635
+ },
636
+ {
637
+ "term": "Heavenly Cathedral",
638
+ "type": "专用",
639
+ "subtype": "场景 Scene",
640
+ "chinese": "天界大教堂场景"
641
+ },
642
+ {
643
+ "term": "monk",
644
+ "type": "专用",
645
+ "subtype": "衣服 Clothing",
646
+ "chinese": "僧侣服饰"
647
+ },
648
+ {
649
+ "term": "diablo style",
650
+ "type": "专用",
651
+ "subtype": "风格 Style",
652
+ "chinese": "暗黑破坏神风格"
653
+ },
654
+ {
655
+ "term": "ultra realistic 8k",
656
+ "type": "通用",
657
+ "subtype": "quality",
658
+ "chinese": "8K超现实精度"
659
+ },
660
+ {
661
+ "term": "cinematic lighting",
662
+ "type": "通用",
663
+ "subtype": "photography",
664
+ "chinese": "电影级布光"
665
+ },
666
+ {
667
+ "term": "hyperdetailed",
668
+ "type": "通用",
669
+ "subtype": "quality",
670
+ "chinese": "超解析细节"
671
+ },
672
+ {
673
+ "term": "neutral colors",
674
+ "type": "通用",
675
+ "subtype": "color",
676
+ "chinese": "中性色调"
677
+ },
678
+ {
679
+ "term": "muted colors",
680
+ "type": "通用",
681
+ "subtype": "color",
682
+ "chinese": "低饱和配色"
683
+ },
684
+ {
685
+ "term": "fine texture",
686
+ "type": "通用",
687
+ "subtype": "quality",
688
+ "chinese": "精细材质纹理"
689
+ },
690
+ {
691
+ "term": "highly detailed",
692
+ "type": "通用",
693
+ "chinese": "高度细节"
694
+ },
695
+ {
696
+ "term": "absurdres",
697
+ "type": "通用",
698
+ "chinese": "超高分辨率"
699
+ },
700
+ {
701
+ "term": "low light",
702
+ "type": "通用",
703
+ "chinese": "低光环境"
704
+ },
705
+ {
706
+ "term": "partially illuminated",
707
+ "type": "通用",
708
+ "chinese": "局部照明"
709
+ },
710
+ {
711
+ "term": "bokeh",
712
+ "type": "通用",
713
+ "chinese": "散景效果"
714
+ },
715
+ {
716
+ "term": "cinematic environment",
717
+ "type": "通用",
718
+ "chinese": "电影级环境"
719
+ },
720
+ {
721
+ "term": "volumetric lighting",
722
+ "type": "通用",
723
+ "chinese": "体积光照"
724
+ },
725
+ {
726
+ "term": "hazy background",
727
+ "type": "通用",
728
+ "chinese": "朦胧背景"
729
+ },
730
+ {
731
+ "term": "high detail",
732
+ "type": "通用",
733
+ "chinese": "高细节度"
734
+ },
735
+ {
736
+ "term": "immersive atmosphere",
737
+ "type": "通用",
738
+ "chinese": "沉浸式氛围"
739
+ },
740
+ {
741
+ "term": "intricate texture",
742
+ "type": "通用",
743
+ "chinese": "复杂纹理"
744
+ },
745
+ {
746
+ "term": "blue eyeshadow",
747
+ "type": "专用",
748
+ "subtype": "眼睛 Eyes",
749
+ "chinese": "蓝色眼影"
750
+ },
751
+ {
752
+ "term": "black coat",
753
+ "type": "专用",
754
+ "subtype": "衣服 Clothing",
755
+ "chinese": "黑色外套"
756
+ },
757
+ {
758
+ "term": "windblown hair",
759
+ "type": "专用",
760
+ "subtype": "头发 Hair",
761
+ "chinese": "风扬发型"
762
+ },
763
+ {
764
+ "term": "white hair",
765
+ "type": "专用",
766
+ "subtype": "头发 Hair",
767
+ "chinese": "白色头发"
768
+ },
769
+ {
770
+ "term": "glowing hair",
771
+ "type": "专用",
772
+ "subtype": "头发 Hair",
773
+ "chinese": "发光发丝"
774
+ },
775
+ {
776
+ "term": "iridescent hair",
777
+ "type": "专用",
778
+ "subtype": "头发 Hair",
779
+ "chinese": "虹彩发色"
780
+ },
781
+ {
782
+ "term": "gradient hair",
783
+ "type": "专用",
784
+ "subtype": "头发 Hair",
785
+ "chinese": "渐变发色"
786
+ },
787
+ {
788
+ "term": "glowing yellow eye",
789
+ "type": "专用",
790
+ "subtype": "眼睛 Eyes",
791
+ "chinese": "发光黄瞳"
792
+ },
793
+ {
794
+ "term": "fiberoptic hair",
795
+ "type": "专用",
796
+ "subtype": "头发 Hair",
797
+ "chinese": "光纤头发"
798
+ },
799
+ {
800
+ "term": "flaming hair",
801
+ "type": "专用",
802
+ "subtype": "头发 Hair",
803
+ "chinese": "火焰发型"
804
+ },
805
+ {
806
+ "term": "perfect details",
807
+ "type": "通用",
808
+ "chinese": "完美细节"
809
+ },
810
+ {
811
+ "term": "illustration",
812
+ "type": "通用",
813
+ "chinese": "插画风格"
814
+ },
815
+ {
816
+ "term": "glasses",
817
+ "type": "专用",
818
+ "subtype": "装饰 Accessory",
819
+ "chinese": "眼镜"
820
+ },
821
+ {
822
+ "term": "shirt",
823
+ "type": "专用",
824
+ "subtype": "衣服 Clothing",
825
+ "chinese": "衬衫"
826
+ },
827
+ {
828
+ "term": "hood",
829
+ "type": "专用",
830
+ "subtype": "衣服 Clothing",
831
+ "chinese": "兜帽"
832
+ },
833
+ {
834
+ "term": "jacket",
835
+ "type": "专用",
836
+ "subtype": "衣服 Clothing",
837
+ "chinese": "夹克"
838
+ },
839
+ {
840
+ "term": "red shirt",
841
+ "type": "专用",
842
+ "subtype": "衣服 Clothing",
843
+ "chinese": "红色衬衫"
844
+ },
845
+ {
846
+ "term": "cloud",
847
+ "type": "专用",
848
+ "subtype": "场景 Scene",
849
+ "chinese": "云朵"
850
+ },
851
+ {
852
+ "term": "black-framed eyewear",
853
+ "type": "专用",
854
+ "subtype": "装饰 Accessory",
855
+ "chinese": "黑框眼镜"
856
+ },
857
+ {
858
+ "term": "long sleeves",
859
+ "type": "专用",
860
+ "subtype": "衣服 Clothing",
861
+ "chinese": "长袖"
862
+ },
863
+ {
864
+ "term": "sky",
865
+ "type": "专用",
866
+ "subtype": "场景 Scene",
867
+ "chinese": "天空"
868
+ },
869
+ {
870
+ "term": "hair between eyes",
871
+ "type": "专用",
872
+ "subtype": "头发 Hair",
873
+ "chinese": "遮眼发型"
874
+ },
875
+ {
876
+ "term": "closed mouth",
877
+ "type": "专用",
878
+ "subtype": "动作 Action",
879
+ "chinese": "闭口"
880
+ },
881
+ {
882
+ "term": "outdoors",
883
+ "type": "专用",
884
+ "subtype": "场景 Scene",
885
+ "chinese": "户外"
886
+ },
887
+ {
888
+ "term": "black jacket",
889
+ "type": "专用",
890
+ "subtype": "衣服 Clothing",
891
+ "chinese": "黑色夹克"
892
+ },
893
+ {
894
+ "term": "short hair",
895
+ "type": "专用",
896
+ "subtype": "头发 Hair",
897
+ "chinese": "短发"
898
+ },
899
+ {
900
+ "term": "hood down",
901
+ "type": "专用",
902
+ "subtype": "衣服 Clothing",
903
+ "chinese": "放下兜帽"
904
+ },
905
+ {
906
+ "term": "sunset",
907
+ "type": "专用",
908
+ "subtype": "场景 Scene",
909
+ "chinese": "日落"
910
+ },
911
+ {
912
+ "term": "hooded jacket",
913
+ "type": "专用",
914
+ "subtype": "衣服 Clothing",
915
+ "chinese": "连帽夹克"
916
+ },
917
+ {
918
+ "term": "hoodie",
919
+ "type": "专用",
920
+ "subtype": "衣服 Clothing",
921
+ "chinese": "连帽衫"
922
+ },
923
+ {
924
+ "term": "sleeves past wrists",
925
+ "type": "专用",
926
+ "subtype": "衣服 Clothing",
927
+ "chinese": "过腕长袖"
928
+ },
929
+ {
930
+ "term": "open jacket",
931
+ "type": "专用",
932
+ "subtype": "衣服 Clothing",
933
+ "chinese": "敞开夹克"
934
+ },
935
+ {
936
+ "term": "dynamic angle",
937
+ "type": "通用",
938
+ "chinese": "动态视角"
939
+ },
940
+ {
941
+ "term": "ultra-detailed",
942
+ "type": "通用",
943
+ "chinese": "超精细细节"
944
+ },
945
+ {
946
+ "term": "fantasy",
947
+ "type": "专用",
948
+ "subtype": "风格 Style",
949
+ "chinese": "奇幻主题"
950
+ },
951
+ {
952
+ "term": "beautiful and detailed eyes",
953
+ "type": "专用",
954
+ "subtype": "眼睛 Eyes",
955
+ "chinese": "精美细致眼瞳"
956
+ },
957
+ {
958
+ "term": "long straight hair",
959
+ "type": "专用",
960
+ "subtype": "头发 Hair",
961
+ "chinese": "直长发"
962
+ },
963
+ {
964
+ "term": "hair flower",
965
+ "type": "专用",
966
+ "subtype": "装饰 Accessory",
967
+ "chinese": "发间花朵饰品"
968
+ },
969
+ {
970
+ "term": "japanese long kimono with flowers",
971
+ "type": "专用",
972
+ "subtype": "衣服 Clothing",
973
+ "chinese": "花卉日式长振袖"
974
+ },
975
+ {
976
+ "term": "detached sleeves",
977
+ "type": "专用",
978
+ "subtype": "衣服 Clothing",
979
+ "chinese": "离脱式袖套"
980
+ },
981
+ {
982
+ "term": "wide sleeves",
983
+ "type": "专用",
984
+ "subtype": "衣服 Clothing",
985
+ "chinese": "广口衣袖"
986
+ },
987
+ {
988
+ "term": "stockings",
989
+ "type": "专用",
990
+ "subtype": "衣服 Clothing",
991
+ "chinese": "长筒袜"
992
+ },
993
+ {
994
+ "term": "detail fingers",
995
+ "type": "通用",
996
+ "chinese": "精细手指描绘"
997
+ },
998
+ {
999
+ "term": "magic dark forest background",
1000
+ "type": "专用",
1001
+ "subtype": "场景 Scene",
1002
+ "chinese": "魔法暗黑森林背景"
1003
+ },
1004
+ {
1005
+ "term": "anime",
1006
+ "type": "通用",
1007
+ "chinese": "动漫风格"
1008
+ },
1009
+ {
1010
+ "term": "2d",
1011
+ "type": "通用",
1012
+ "chinese": "二维平面"
1013
+ },
1014
+ {
1015
+ "term": "ghibli style",
1016
+ "type": "通用",
1017
+ "chinese": "吉卜力画风"
1018
+ },
1019
+ {
1020
+ "term": "white fox tail",
1021
+ "type": "专用",
1022
+ "subtype": "装饰 Accessory",
1023
+ "chinese": "白狐尾巴"
1024
+ },
1025
+ {
1026
+ "term": "black pantyhose",
1027
+ "type": "专用",
1028
+ "subtype": "衣服 Clothing",
1029
+ "chinese": "黑色连裤袜"
1030
+ },
1031
+ {
1032
+ "term": "blue eyes",
1033
+ "type": "专用",
1034
+ "subtype": "眼睛 Eyes",
1035
+ "chinese": "蓝色眼睛"
1036
+ }
1037
+ ]
1038
+ }
client_jp/app.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_file, send_from_directory
2
+ import os
3
+ import requests
4
+ from PIL import Image
5
+ import io
6
+
7
+ def generate_image(api_url, positive_prompt, negative_prompt=""):
8
+ payload = {
9
+ "positive_prompt": positive_prompt,
10
+ "negative_prompt": negative_prompt,
11
+ }
12
+
13
+ try:
14
+ response = requests.post(
15
+ f"{api_url}/generate",
16
+ json=payload,
17
+ timeout=30
18
+ )
19
+
20
+ if response.status_code == 200:
21
+ return Image.open(io.BytesIO(response.content))
22
+ else:
23
+ error_info = response.json().get("detail", "Unknown error")
24
+ print(f"生成失败 ({response.status_code}): {error_info}")
25
+
26
+ except Exception as e:
27
+ print(f"API调用异常: {str(e)}")
28
+
29
+
30
+ app = Flask(__name__)
31
+
32
+ # Serve static files from the current directory
33
+ @app.route('/<path:filename>')
34
+ def serve_static(filename):
35
+ return send_from_directory('.', filename)
36
+
37
+ @app.route('/')
38
+ def index():
39
+ return send_file('index.html')
40
+
41
+ @app.route('/generate', methods=['POST'])
42
+ def generate():
43
+ data = request.json
44
+ positive_prompt = ", ".join(data['terms'])
45
+
46
+ # Call image generation
47
+ image = generate_image(
48
+ "http://192.168.20.113:7888",
49
+ positive_prompt=positive_prompt,
50
+ negative_prompt="open cloth,pornographic,violence,wearing less,signature, soft, blurry, drawing, sketch, poor quality, ugly, text, type, word, logo, pixelated, low resolution, saturated, high contrast, oversharpened"
51
+ )
52
+
53
+ if image:
54
+ image_path = "generated_image.png"
55
+ image.save(image_path)
56
+ return send_file(image_path, mimetype='image/png')
57
+ else:
58
+ return jsonify({"error": "Image generation failed"}), 500
59
+
60
+ if __name__ == '__main__':
61
+ app.run(port=5000, debug=True)
client_jp/generated_image.png ADDED

Git LFS Details

  • SHA256: a862a4de39afd680d5602fc2171750433c99fb52cbed8fe9f521c85de1795e41
  • Pointer size: 131 Bytes
  • Size of remote file: 251 kB
client_jp/index.html ADDED
@@ -0,0 +1,990 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>M5Stack LLM8850 画像生成展示</title>
8
+ <style>
9
+ :root {
10
+ --primary-color: #3498db;
11
+ --selected-color: #e74c3c;
12
+ --success-color: #27ae60;
13
+ --warning-color: #f39c12;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
18
+ margin: 0;
19
+ padding: 20px;
20
+ background: #f0f3f5;
21
+ padding-bottom: 120px;
22
+ /* 为固定输入框预留空间 */
23
+ }
24
+
25
+ .container {
26
+ max-width: 100%;
27
+ margin: 0 auto;
28
+ background: white;
29
+ border-radius: 12px;
30
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
31
+ padding: 2rem;
32
+ position: relative;
33
+ }
34
+
35
+ /* 会社ロゴ */
36
+ .company-logo {
37
+ position: absolute;
38
+ top: 20px;
39
+ right: 20px;
40
+ width: 80px;
41
+ height: auto;
42
+ }
43
+
44
+ h1 {
45
+ text-align: center;
46
+ color: #2c3e50;
47
+ margin-bottom: 2rem;
48
+ font-weight: 600;
49
+ margin-right: 100px;
50
+ /* 为图标留出空间 */
51
+ }
52
+
53
+ /* 選択された項目のエリアスタイル */
54
+ #selected-terms-box {
55
+ position: sticky;
56
+ top: 0;
57
+ background: rgba(255, 255, 255, 0.95);
58
+ backdrop-filter: blur(5px);
59
+ z-index: 10;
60
+ padding: 1rem;
61
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
62
+ margin-bottom: 1.5rem;
63
+ border-radius: 8px;
64
+ }
65
+
66
+ .selected-terms-label {
67
+ font-weight: 500;
68
+ color: #2c3e50;
69
+ margin-bottom: 0.5rem;
70
+ font-size: 0.9rem;
71
+ }
72
+
73
+ .selected-term {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ padding: 0.4rem 0.8rem;
77
+ background: var(--selected-color);
78
+ color: white;
79
+ border-radius: 20px;
80
+ margin: 0.3rem;
81
+ font-size: 0.9em;
82
+ animation: popIn 0.2s ease;
83
+ cursor: pointer;
84
+ transition: all 0.2s ease;
85
+ }
86
+
87
+ .selected-term:hover {
88
+ background: #c0392b;
89
+ transform: scale(1.05);
90
+ }
91
+
92
+ .controls {
93
+ display: inline-flex;
94
+ gap: 0.5rem;
95
+ margin-left: 1rem;
96
+ vertical-align: middle;
97
+ }
98
+
99
+ .btn {
100
+ padding: 0.6rem 1.2rem;
101
+ border: none;
102
+ border-radius: 20px;
103
+ font-size: 0.9rem;
104
+ cursor: pointer;
105
+ transition: all 0.2s ease;
106
+ font-weight: 500;
107
+ }
108
+
109
+ #generate-btn {
110
+ background: var(--primary-color);
111
+ color: white;
112
+ padding: 1rem 2rem;
113
+ /* 放大生成按钮 */
114
+ font-size: 1.1rem;
115
+ font-weight: 600;
116
+ }
117
+
118
+ #random-btn {
119
+ background: var(--success-color);
120
+ color: white;
121
+ }
122
+
123
+ #clear-terms-btn {
124
+ background: var(--warning-color);
125
+ color: white;
126
+ }
127
+
128
+ #clear-images-btn {
129
+ background: #95a5a6;
130
+ color: white;
131
+ }
132
+
133
+ .btn:hover {
134
+ transform: translateY(-2px);
135
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
136
+ }
137
+
138
+ .btn:disabled {
139
+ background: #bdc3c7;
140
+ cursor: not-allowed;
141
+ transform: none;
142
+ box-shadow: none;
143
+ }
144
+
145
+ @keyframes popIn {
146
+ from {
147
+ transform: scale(0.8);
148
+ opacity: 0;
149
+ }
150
+
151
+ to {
152
+ transform: scale(1);
153
+ opacity: 1;
154
+ }
155
+ }
156
+
157
+ /* プログレスバーのスタイル(非ポップアップ式) */
158
+ .progress-container {
159
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
160
+ padding: 1rem;
161
+ border-radius: 8px;
162
+ margin-bottom: 1rem;
163
+ color: white;
164
+ display: none;
165
+ animation: slideDown 0.3s ease;
166
+ }
167
+
168
+ .progress-container.active {
169
+ display: block;
170
+ }
171
+
172
+ .progress-bar {
173
+ width: 100%;
174
+ height: 6px;
175
+ background: rgba(255, 255, 255, 0.3);
176
+ border-radius: 3px;
177
+ overflow: hidden;
178
+ margin: 0.5rem 0;
179
+ }
180
+
181
+ .progress-fill {
182
+ height: 100%;
183
+ background: linear-gradient(90deg, #fff, #f39c12);
184
+ width: 0%;
185
+ transition: width 0.3s ease;
186
+ border-radius: 3px;
187
+ }
188
+
189
+ .progress-info {
190
+ display: flex;
191
+ justify-content: space-between;
192
+ align-items: center;
193
+ font-size: 0.9rem;
194
+ }
195
+
196
+ .progress-step {
197
+ opacity: 0.9;
198
+ }
199
+
200
+ .fun-fact {
201
+ background: rgba(255, 255, 255, 0.1);
202
+ padding: 0.5rem;
203
+ border-radius: 4px;
204
+ margin-top: 0.5rem;
205
+ font-style: italic;
206
+ font-size: 0.85rem;
207
+ animation: fadeIn 0.5s ease;
208
+ }
209
+
210
+ @keyframes slideDown {
211
+ from {
212
+ opacity: 0;
213
+ transform: translateY(-20px);
214
+ }
215
+
216
+ to {
217
+ opacity: 1;
218
+ transform: translateY(0);
219
+ }
220
+ }
221
+
222
+ @keyframes fadeIn {
223
+ from {
224
+ opacity: 0;
225
+ transform: translateY(10px);
226
+ }
227
+
228
+ to {
229
+ opacity: 1;
230
+ transform: translateY(0);
231
+ }
232
+ }
233
+
234
+ /* 項目分類のスタイル */
235
+ #term-categories {
236
+ display: grid;
237
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
238
+ gap: 1.5rem;
239
+ }
240
+
241
+ .category {
242
+ background: #ffffff;
243
+ border-radius: 8px;
244
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
245
+ overflow: hidden;
246
+ }
247
+
248
+ .category-header {
249
+ padding: 1rem;
250
+ background: var(--primary-color);
251
+ color: white;
252
+ font-weight: 500;
253
+ position: sticky;
254
+ top: 0;
255
+ z-index: 1;
256
+ }
257
+
258
+ .scroll-container {
259
+ max-height: 240px;
260
+ overflow-y: hidden;
261
+ padding: 1rem;
262
+ position: relative;
263
+ }
264
+
265
+ .term-item {
266
+ padding: 0.8rem 1.2rem;
267
+ margin: 0.5rem 0;
268
+ border-radius: 6px;
269
+ background: #f8f9fa;
270
+ cursor: pointer;
271
+ transition: all 0.2s ease;
272
+ position: relative;
273
+ overflow: hidden;
274
+ display: flex;
275
+ align-items: center;
276
+ min-height: 48px;
277
+ }
278
+
279
+ .term-content {
280
+ display: flex;
281
+ flex-direction: column;
282
+ gap: 0.2rem;
283
+ }
284
+
285
+ .japanese {
286
+ font-weight: 500;
287
+ color: #2c3e50;
288
+ }
289
+
290
+ .term {
291
+ font-size: 0.85rem;
292
+ color: #7f8c8d;
293
+ font-style: italic;
294
+ }
295
+
296
+ .term-item.selected {
297
+ background: var(--primary-color);
298
+ color: white;
299
+ }
300
+
301
+ .term-item.selected .term {
302
+ color: rgba(255, 255, 255, 0.8);
303
+ }
304
+
305
+ .term-item:hover {
306
+ transform: translateX(5px);
307
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
308
+ }
309
+
310
+ /* レイアウト調整 - 画面全体に広げる */
311
+ .main-content {
312
+ display: grid;
313
+ grid-template-columns: 1fr 500px;
314
+ gap: 2rem;
315
+ min-height: 70vh;
316
+ }
317
+
318
+ .left-column {
319
+ display: grid;
320
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
321
+ gap: 1.2rem;
322
+ align-content: start;
323
+ }
324
+
325
+ .right-column {
326
+ background: #f8f9fa;
327
+ border-radius: 8px;
328
+ padding: 1rem;
329
+ display: flex;
330
+ flex-direction: column;
331
+ }
332
+
333
+ .images-header {
334
+ text-align: center;
335
+ color: #2c3e50;
336
+ margin-bottom: 1rem;
337
+ font-size: 1.1rem;
338
+ font-weight: 500;
339
+ flex-shrink: 0;
340
+ }
341
+
342
+ /* 画像コンテナを2列に変更 */
343
+ #images-container {
344
+ display: grid;
345
+ grid-template-columns: 1fr 1fr;
346
+ gap: 1rem;
347
+ flex: 1;
348
+ }
349
+
350
+ .image-item {
351
+ background: white;
352
+ border-radius: 8px;
353
+ padding: 0.5rem;
354
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
355
+ animation: zoomIn 0.3s ease;
356
+ align-self: start;
357
+ }
358
+
359
+ .image-item img {
360
+ width: 100%;
361
+ height: auto;
362
+ border-radius: 6px;
363
+ display: block;
364
+ }
365
+
366
+ .image-terms {
367
+ font-size: 0.75rem;
368
+ color: #7f8c8d;
369
+ margin-top: 0.5rem;
370
+ padding: 0.5rem;
371
+ background: #ecf0f1;
372
+ border-radius: 4px;
373
+ word-wrap: break-word;
374
+ line-height: 1.3;
375
+ }
376
+
377
+ .empty-state {
378
+ grid-column: 1 / -1;
379
+ text-align: center;
380
+ color: #7f8c8d;
381
+ padding: 2rem;
382
+ font-style: italic;
383
+ }
384
+
385
+ @keyframes zoomIn {
386
+ from {
387
+ opacity: 0;
388
+ transform: scale(0.9);
389
+ }
390
+
391
+ to {
392
+ opacity: 1;
393
+ transform: scale(1);
394
+ }
395
+ }
396
+
397
+ /* レスポンシブデザイン */
398
+ @media (max-width: 1400px) {
399
+ .main-content {
400
+ grid-template-columns: 1fr 450px;
401
+ }
402
+ }
403
+
404
+ @media (max-width: 1200px) {
405
+ .main-content {
406
+ grid-template-columns: 1fr;
407
+ }
408
+ }
409
+
410
+ @media (max-width: 768px) {
411
+ .container {
412
+ padding: 1rem;
413
+ }
414
+
415
+ .company-logo {
416
+ width: 60px;
417
+ top: 10px;
418
+ right: 10px;
419
+ }
420
+
421
+ h1 {
422
+ margin-right: 70px;
423
+ font-size: 1.5rem;
424
+ }
425
+
426
+ #term-categories {
427
+ grid-template-columns: 1fr;
428
+ }
429
+
430
+ #images-container {
431
+ grid-template-columns: 1fr;
432
+ }
433
+
434
+ .controls {
435
+ flex-direction: column;
436
+ gap: 0.5rem;
437
+ margin-left: 0;
438
+ margin-top: 1rem;
439
+ }
440
+
441
+ .btn {
442
+ padding: 0.8rem 1.5rem;
443
+ }
444
+
445
+ #generate-btn {
446
+ padding: 1rem 1.5rem;
447
+ }
448
+ }
449
+
450
+ /* 画面全体に広げる調整 */
451
+ @media (min-width: 1600px) {
452
+ .container {
453
+ max-width: 95%;
454
+ }
455
+
456
+ .main-content {
457
+ grid-template-columns: 1fr 600px;
458
+ }
459
+
460
+ .left-column {
461
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
462
+ }
463
+ }
464
+
465
+ /* 手动输入区域样式 */
466
+ .manual-input-container {
467
+ position: fixed;
468
+ bottom: 0;
469
+ left: 0;
470
+ right: 0;
471
+ background: #ffffff;
472
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
473
+ border-top: 1px solid #e1e8ed;
474
+ z-index: 100;
475
+ padding: 1rem 2rem;
476
+ margin: 0;
477
+ }
478
+
479
+ .input-header {
480
+ font-weight: 500;
481
+ color: #2c3e50;
482
+ margin-bottom: 1rem;
483
+ font-size: 1rem;
484
+ }
485
+
486
+ .input-wrapper {
487
+ display: flex;
488
+ gap: 1rem;
489
+ margin-bottom: 0.5rem;
490
+ }
491
+
492
+ #manual-term-input {
493
+ flex: 1;
494
+ padding: 0.8rem 1.2rem;
495
+ border: 1px solid #ddd;
496
+ border-radius: 20px;
497
+ font-size: 0.9rem;
498
+ transition: all 0.2s ease;
499
+ }
500
+
501
+ #manual-term-input:focus {
502
+ outline: none;
503
+ border-color: var(--primary-color);
504
+ box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
505
+ }
506
+
507
+ #add-term-btn {
508
+ padding: 0.8rem 1.5rem;
509
+ white-space: nowrap;
510
+ }
511
+
512
+ .input-note {
513
+ font-size: 0.8rem;
514
+ color: #7f8c8d;
515
+ font-style: italic;
516
+ }
517
+
518
+ /* 响应式设计 */
519
+ @media (max-width: 768px) {
520
+ .input-wrapper {
521
+ flex-direction: column;
522
+ }
523
+
524
+ #add-term-btn {
525
+ align-self: flex-start;
526
+ }
527
+ }
528
+ </style>
529
+ </head>
530
+
531
+ <body>
532
+ <div class="container">
533
+ <!-- 公司图标 -->
534
+ <img src="https://docs.m5stack.com/assets/m5logo2022.svg" alt="M5Stack Logo" class="company-logo">
535
+
536
+ <h1>M5Stack AI Pyramid AX8850 画像生成展示</h1>
537
+
538
+ <div id="selected-terms-box">
539
+ <div class="selected-terms-label">選択されたプロンプト Selected Prompts:</div>
540
+ <div id="selected-terms-list"></div>
541
+ <div class="controls">
542
+ <button id="generate-btn" class="btn">今すぐ生成 Generate Now</button>
543
+ <button id="random-btn" class="btn">ランダム記述 Random Terms</button>
544
+ <button id="clear-terms-btn" class="btn">プロンプトをクリア Clear Terms</button>
545
+ <button id="clear-images-btn" class="btn">画像をクリア Clear Images</button>
546
+ </div>
547
+ </div>
548
+
549
+ <!-- 非弹出式进度条 -->
550
+ <div class="progress-container" id="progress-container">
551
+ <div class="progress-info">
552
+ <span>AI が創作中... AI is creating...</span>
553
+ <span id="progress-percent">0%</span>
554
+ </div>
555
+ <div class="progress-bar">
556
+ <div class="progress-fill" id="progress-fill"></div>
557
+ </div>
558
+ <div class="progress-step" id="progress-step">初期化中... Initializing...</div>
559
+ <div class="fun-fact" id="fun-fact"></div>
560
+ </div>
561
+
562
+ <div class="main-content">
563
+ <div class="left-column">
564
+ <div id="term-categories"></div>
565
+ </div>
566
+
567
+ <div class="right-column">
568
+ <div class="images-header">生成履歴 Generation History</div>
569
+ <div id="images-container">
570
+ <div class="empty-state">
571
+ キーワードを選択し、生成ボタンをクリックして創作を開始してください<br>
572
+ Select terms and click generate to start creating
573
+ </div>
574
+ </div>
575
+ </div>
576
+ </div>
577
+
578
+ <!-- 手动输入提示词区域 -->
579
+ <div class="manual-input-container">
580
+ <div class="input-header">手動入力 Manual Input:</div>
581
+ <div class="input-wrapper">
582
+ <input type="text" id="manual-term-input"
583
+ placeholder="英語の形容詞を入力してください (例: beautiful, dark, fantasy) - Please enter an English adjective">
584
+ <button id="add-term-btn" class="btn">追加 Add</button>
585
+ </div>
586
+ <div class="input-note">※ 単一の英語形容詞を入力してください - Please enter a single English adjective</div>
587
+ </div>
588
+ </div>
589
+
590
+ <script>
591
+ let scrollControllers = new Map();
592
+ // 有趣的提示词汇
593
+ const funFacts = [
594
+ "あなたの創造的なアイデアを分析中... Analyzing your creative ideas...",
595
+ "AIブレインが最適な構図を考え中... AI brain thinking about optimal composition...",
596
+ "パレット準備中、完璧な色を探しています... Preparing palette, finding perfect colors...",
597
+ "ピクセルスプライトが組み合わせ待ち列に並んでいます... Pixel sprites lining up for combination...",
598
+ "魔法で文字を視覚に変換中... Magic transforming text to visuals...",
599
+ "クリエイティブファクトリー全速力運転中... Creative factory at full speed...",
600
+ "各ディテールを精巧に彫刻中... Every detail carefully crafted...",
601
+ "ライトマスターが明暗を調整中... Light master adjusting brightness...",
602
+ "ブラシがキャンバス上で舞っています... Brushes dancing on canvas...",
603
+ "芸術的インスピレーションが形になりつつあります... Artistic inspiration taking shape...",
604
+ "創造性エンジン全開... Creativity engine at full power...",
605
+ "美学アルゴリズムがディテールを最適化中... Aesthetic algorithm optimizing details...",
606
+ "ビジュアルシンフォニーが演奏開始予定... Visual symphony about to play...",
607
+ "想像力が境界を突破中... Imagination breaking boundaries...",
608
+ "ミラクルワークショップが魔法をかけ中... Miracle workshop casting magic..."
609
+ ];
610
+
611
+ // UNet去噪步骤提示
612
+ const unetSteps = [
613
+ "入力レイヤーの前処理中... Preprocessing input layers...",
614
+ "第1層CNN処理中... Layer 1 CNN processing...",
615
+ "第2層特徴抽出中... Layer 2 feature extraction...",
616
+ "第3層セマンティック理解... Layer 3 semantic understanding...",
617
+ "第4層ディテール最適化... Layer 4 detail optimization...",
618
+ "第5層カラー調和... Layer 5 color harmony...",
619
+ "第6層テクスチャ生成... Layer 6 texture generation...",
620
+ "第7層構図調整... Layer 7 composition adjustment...",
621
+ "第8層ライティング処理... Layer 8 lighting processing...",
622
+ "第9層ディテール強化... Layer 9 detail enhancement...",
623
+ "第10層品質チェック... Layer 10 quality check...",
624
+ "第11層スタイル融合... Layer 11 style fusion...",
625
+ "第12層最終カラー調整... Layer 12 final coloring...",
626
+ "第13層シャープ化処理... Layer 13 sharpening...",
627
+ "第14層ノイズ除去... Layer 14 noise removal...",
628
+ "第15層コントラスト最適化... Layer 15 contrast optimization...",
629
+ "第16層彩度調整... Layer 16 saturation adjustment...",
630
+ "第17層最終レンダリング... Layer 17 final rendering...",
631
+ "第18層品質検証... Layer 18 quality validation...",
632
+ "第19層出力準備... Layer 19 output preparation...",
633
+ "第20層処理完了... Layer 20 completion..."
634
+ ];
635
+
636
+ async function loadAndDisplayTerms() {
637
+ try {
638
+ const response = await fetch('./person_jp.json');
639
+ const data = await response.json();
640
+ const proprietaryTerms = data.prompt_terms.filter(term => term.type === "专用");
641
+ const categories = proprietaryTerms.reduce((acc, term) => {
642
+ const subtype = term.subtype || "通用 General";
643
+ acc[subtype] = acc[subtype] || [];
644
+ acc[subtype].push(term);
645
+ return acc;
646
+ }, {});
647
+ const container = document.getElementById('term-categories');
648
+ Object.entries(categories).forEach(([subtype, terms]) => {
649
+ const category = document.createElement('div');
650
+ category.className = 'category';
651
+ const header = document.createElement('div');
652
+ header.className = 'category-header';
653
+ header.textContent = subtype;
654
+ const scrollContainer = document.createElement('div');
655
+ scrollContainer.className = 'scroll-container';
656
+ terms.forEach(term => {
657
+ const item = document.createElement('div');
658
+ item.className = 'term-item';
659
+ item.dataset.term = term.term;
660
+ item.innerHTML = `
661
+ <div class="term-content">
662
+ <div class="japanese">${term.japanese}</div>
663
+ <div class="term">${term.term}</div>
664
+ </div>
665
+ `;
666
+ scrollContainer.appendChild(item);
667
+ });
668
+ category.append(header, scrollContainer);
669
+ container.appendChild(category);
670
+ if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
671
+ setupAutoScroll(scrollContainer);
672
+ }
673
+ });
674
+ } catch (error) {
675
+ console.error('データ読み込み失敗 Data loading failed:', error);
676
+ }
677
+ }
678
+
679
+ function setupAutoScroll(container) {
680
+ let isPaused = false;
681
+ let scrollPos = 0;
682
+ const scrollSpeed = 0.5;
683
+ const scrollHeight = container.scrollHeight - container.clientHeight;
684
+ container.addEventListener('mouseenter', () => isPaused = true);
685
+ container.addEventListener('mouseleave', () => isPaused = false);
686
+ const scroll = () => {
687
+ if (!isPaused && scrollHeight > 0) {
688
+ scrollPos = (scrollPos + scrollSpeed) % scrollHeight;
689
+ const easedPos = scrollPos < scrollHeight / 2 ? scrollPos : scrollHeight - scrollPos;
690
+ container.scrollTop = easedPos;
691
+ }
692
+ requestAnimationFrame(scroll);
693
+ };
694
+ scroll();
695
+ }
696
+
697
+ function updateSelections() {
698
+ const selectedItems = Array.from(document.querySelectorAll('.term-item.selected'));
699
+ const container = document.getElementById('selected-terms-list');
700
+
701
+ // 保存手动添加的提示词
702
+ const manualTerms = [];
703
+ const existingSelectedTerms = container.querySelectorAll('.selected-term');
704
+ existingSelectedTerms.forEach(termElement => {
705
+ const term = termElement.dataset.term;
706
+ // 检查是否是手动添加的(没有对应的.term-item)
707
+ const hasTermItem = document.querySelector(`.term-item[data-term="${term}"]`);
708
+ if (!hasTermItem) {
709
+ manualTerms.push({
710
+ term: term,
711
+ element: termElement.cloneNode(true)
712
+ });
713
+ }
714
+ });
715
+
716
+ // 重新生成选中提示词列表
717
+ container.innerHTML = selectedItems.map(item => {
718
+ const japanese = item.querySelector('.japanese').textContent;
719
+ const english = item.querySelector('.term').textContent;
720
+ return `<span class="selected-term" data-term="${english}">${japanese} ${english}</span>`;
721
+ }).join('');
722
+
723
+ // 重新添加手动添加的提示词
724
+ manualTerms.forEach(manualTerm => {
725
+ container.appendChild(manualTerm.element);
726
+ });
727
+ }
728
+
729
+ function showProgress() {
730
+ const container = document.getElementById('progress-container');
731
+ const progressFill = document.getElementById('progress-fill');
732
+ const progressStep = document.getElementById('progress-step');
733
+ const progressPercent = document.getElementById('progress-percent');
734
+ const funFact = document.getElementById('fun-fact');
735
+ container.classList.add('active');
736
+ let currentStep = 0;
737
+ const totalSteps = 20;
738
+ const stepDuration = 240; //进度条刷新时间
739
+ return new Promise((resolve) => {
740
+ const interval = setInterval(() => {
741
+ currentStep++;
742
+ const progress = (currentStep / totalSteps) * 100;
743
+ progressFill.style.width = progress + '%';
744
+ progressPercent.textContent = Math.round(progress) + '%';
745
+ progressStep.textContent = unetSteps[currentStep - 1] || '処理中... Processing...';
746
+ if (currentStep % 3 === 0) {
747
+ const randomFact = funFacts[Math.floor(Math.random() * funFacts.length)];
748
+ funFact.textContent = randomFact;
749
+ }
750
+ if (currentStep >= totalSteps) {
751
+ clearInterval(interval);
752
+ progressStep.textContent = 'まもなく完了... Almost done...';
753
+ setTimeout(() => {
754
+ container.classList.remove('active');
755
+ resolve();
756
+ }, 500);
757
+ }
758
+ }, stepDuration);
759
+ });
760
+ }
761
+
762
+ function addImageToHistory(selectedTerms) {
763
+ const imagesContainer = document.getElementById('images-container');
764
+ // 清空初始提示
765
+ const emptyState = imagesContainer.querySelector('.empty-state');
766
+ if (emptyState) {
767
+ emptyState.remove();
768
+ }
769
+ const imgContainer = document.createElement('div');
770
+ imgContainer.className = 'image-item';
771
+ const img = document.createElement('img');
772
+ img.src = 'generated_image.png?' + new Date().getTime();
773
+ img.alt = 'Generated Image';
774
+ const termsDiv = document.createElement('div');
775
+ termsDiv.className = 'image-terms';
776
+ termsDiv.textContent = '关键词 Keywords: ' + selectedTerms.join(', ');
777
+ imgContainer.appendChild(img);
778
+ imgContainer.appendChild(termsDiv);
779
+ // 添加到开头
780
+ imagesContainer.prepend(imgContainer);
781
+ // 限制历史记录数量
782
+ while (imagesContainer.children.length > 20) {
783
+ imagesContainer.removeChild(imagesContainer.lastChild);
784
+ }
785
+ }
786
+
787
+ function clearAllTerms() {
788
+ // 清除所有选中状态
789
+ document.querySelectorAll('.term-item.selected').forEach(item => {
790
+ item.classList.remove('selected');
791
+ });
792
+
793
+ // 清除手动添加的词条
794
+ const container = document.getElementById('selected-terms-list');
795
+ const manualTerms = container.querySelectorAll('.selected-term');
796
+ manualTerms.forEach(term => {
797
+ // 检查是否是手动添加的(没有对应的.term-item)
798
+ const termValue = term.dataset.term;
799
+ const hasTermItem = document.querySelector(`.term-item[data-term="${termValue}"]`);
800
+ if (!hasTermItem) {
801
+ term.remove();
802
+ }
803
+ });
804
+
805
+ updateSelections();
806
+ }
807
+
808
+ function clearAllImages() {
809
+ const imagesContainer = document.getElementById('images-container');
810
+ imagesContainer.innerHTML = '<div class="empty-state">項目を選択して生成ボタンをクリックして創作を開始してください<br>Select terms and click generate to start creating</div>';
811
+ }
812
+
813
+ // 随机选择每个类别中的一个提示词
814
+ function selectRandomTerms() {
815
+ // 先清除所有已选择的词条
816
+ clearAllTerms();
817
+
818
+ // 获取所有类别
819
+ const categories = document.querySelectorAll('.category');
820
+ const randomTerms = [];
821
+
822
+ categories.forEach(category => {
823
+ const termItems = category.querySelectorAll('.term-item');
824
+ if (termItems.length > 0) {
825
+ // 从每个类别中随机选择一个
826
+ const randomIndex = Math.floor(Math.random() * termItems.length);
827
+ const selectedItem = termItems[randomIndex];
828
+ selectedItem.classList.add('selected');
829
+ randomTerms.push({
830
+ japanese: selectedItem.querySelector('.japanese').textContent,
831
+ english: selectedItem.querySelector('.term').textContent
832
+ });
833
+ }
834
+ });
835
+
836
+ // 更新选中的词条显示
837
+ updateSelections();
838
+
839
+ // 可选:显示一个提示告诉用户选择了哪些词条
840
+ if (randomTerms.length > 0) {
841
+ console.log('ランダムに選ばれた用語:', randomTerms);
842
+ // 可以添加一个简短的提示
843
+ const notification = document.createElement('div');
844
+ notification.style.cssText = `
845
+ position: fixed;
846
+ top: 20px;
847
+ left: 50%;
848
+ transform: translateX(-50%);
849
+ background: var(--success-color);
850
+ color: white;
851
+ padding: 0.8rem 1.5rem;
852
+ border-radius: 20px;
853
+ z-index: 1000;
854
+ animation: slideDown 0.3s ease;
855
+ `;
856
+ notification.textContent = `${randomTerms.length}個の条項がランダムに選択されました Randomly selected ${randomTerms.length} terms`;
857
+ document.body.appendChild(notification);
858
+
859
+ // 3秒后移除提示
860
+ setTimeout(() => {
861
+ notification.remove();
862
+ }, 3000);
863
+ }
864
+ }
865
+
866
+ // 事件监听
867
+ document.addEventListener('click', (e) => {
868
+ // 点击词条选择/取消选择
869
+ if (e.target.closest('.term-item')) {
870
+ const item = e.target.closest('.term-item');
871
+ item.classList.toggle('selected');
872
+ updateSelections();
873
+ }
874
+ // 点击已选择的词条气泡取消选择
875
+ if (e.target.closest('.selected-term')) {
876
+ const term = e.target.closest('.selected-term').dataset.term;
877
+ const termItem = document.querySelector(`.term-item[data-term="${term}"]`);
878
+ if (termItem) {
879
+ termItem.classList.remove('selected');
880
+ updateSelections();
881
+ } else {
882
+ // 如果是手动添加的提示词,直接移除元素
883
+ e.target.closest('.selected-term').remove();
884
+ }
885
+ }
886
+ });
887
+
888
+ window.addEventListener('load', () => {
889
+ loadAndDisplayTerms();
890
+ const generateBtn = document.getElementById('generate-btn');
891
+ const randomBtn = document.getElementById('random-btn');
892
+ const clearTermsBtn = document.getElementById('clear-terms-btn');
893
+ const clearImagesBtn = document.getElementById('clear-images-btn');
894
+ const addTermBtn = document.getElementById('add-term-btn');
895
+ const manualTermInput = document.getElementById('manual-term-input');
896
+
897
+ // 生成按钮
898
+ generateBtn.addEventListener('click', async () => {
899
+ // 获取预定义的选中词条
900
+ const predefinedTerms = Array.from(document.querySelectorAll('.term-item.selected'))
901
+ .map(item => item.dataset.term);
902
+
903
+ // 获取手动输入的词条
904
+ const manualTerms = Array.from(document.querySelectorAll('#selected-terms-list .selected-term'))
905
+ .map(item => item.dataset.term)
906
+ .filter(term => {
907
+ // 过滤掉预定义的词条,避免重复
908
+ return !predefinedTerms.includes(term);
909
+ });
910
+
911
+ // 合并所有词条
912
+ const selectedTerms = [...predefinedTerms, ...manualTerms];
913
+
914
+ if (selectedTerms.length === 0) {
915
+ alert('少なくとも1つのキーワードを選択してください Please select at least one term');
916
+ return;
917
+ }
918
+ generateBtn.disabled = true;
919
+ const progressPromise = showProgress();
920
+ try {
921
+ const [response] = await Promise.all([
922
+ fetch('/generate', {
923
+ method: 'POST',
924
+ headers: {
925
+ 'Content-Type': 'application/json'
926
+ },
927
+ body: JSON.stringify({ terms: selectedTerms })
928
+ }),
929
+ progressPromise
930
+ ]);
931
+ if (response.ok) {
932
+ addImageToHistory(selectedTerms);
933
+ } else {
934
+ const error = await response.json();
935
+ alert(`生成失敗 Generation failed: ${error.error}`);
936
+ }
937
+ } catch (error) {
938
+ console.error('生成リクエストに失敗しました Generation request failed:', error);
939
+ alert('生成リクエストに失敗しました Generation request failed, please check network connection');
940
+ } finally {
941
+ generateBtn.disabled = false;
942
+ }
943
+ });
944
+ randomBtn.addEventListener('click', () => {
945
+ selectRandomTerms();
946
+ });
947
+
948
+ // 清除提示词按钮
949
+ clearTermsBtn.addEventListener('click', clearAllTerms);
950
+
951
+ // 清除图片按钮
952
+ clearImagesBtn.addEventListener('click', () => {
953
+ if (confirm('生成されたすべての画像を削除してもよろしいですか? Are you sure you want to clear all generated images?')) {
954
+ clearAllImages();
955
+ }
956
+ });
957
+
958
+ // 添加手动输入的提示词
959
+ addTermBtn.addEventListener('click', () => {
960
+ const term = manualTermInput.value.trim();
961
+ if (term) {
962
+ // 创建一个新的选中项
963
+ const selectedTermsList = document.getElementById('selected-terms-list');
964
+ const existingTerm = selectedTermsList.querySelector(`.selected-term[data-term="${term}"]`);
965
+
966
+ // 避免重复添加
967
+ if (!existingTerm) {
968
+ const span = document.createElement('span');
969
+ span.className = 'selected-term';
970
+ span.dataset.term = term;
971
+ span.textContent = term;
972
+ selectedTermsList.appendChild(span);
973
+ }
974
+
975
+ // 清空输入框
976
+ manualTermInput.value = '';
977
+ }
978
+ });
979
+
980
+ // 回车键添加提示词
981
+ manualTermInput.addEventListener('keypress', (e) => {
982
+ if (e.key === 'Enter') {
983
+ addTermBtn.click();
984
+ }
985
+ });
986
+ });
987
+ </script>
988
+ </body>
989
+
990
+ </html>
client_jp/person.json ADDED
@@ -0,0 +1,1038 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "prompt_terms": [
3
+ {
4
+ "term": "masterpiece",
5
+ "type": "通用",
6
+ "chinese": "杰作级别"
7
+ },
8
+ {
9
+ "term": "fox tail",
10
+ "type": "专用",
11
+ "subtype": "装饰 Accessory",
12
+ "chinese": "狐狸尾巴"
13
+ },
14
+ {
15
+ "term": "crystal tiara",
16
+ "type": "专用",
17
+ "subtype": "装饰 Accessory",
18
+ "chinese": "水晶王冠"
19
+ },
20
+ {
21
+ "term": "feather hairpin",
22
+ "type": "专用",
23
+ "subtype": "装饰 Accessory",
24
+ "chinese": "羽毛发夹"
25
+ },
26
+ {
27
+ "term": "butterfly wings",
28
+ "type": "专用",
29
+ "subtype": "装饰 Accessory",
30
+ "chinese": "蝴蝶翅膀"
31
+ },
32
+ {
33
+ "term": "star-shaped earrings",
34
+ "type": "专用",
35
+ "subtype": "装饰 Accessory",
36
+ "chinese": "星星耳饰"
37
+ },
38
+ {
39
+ "term": "ribbon choker",
40
+ "type": "专用",
41
+ "subtype": "装饰 Accessory",
42
+ "chinese": "缎带项圈"
43
+ },
44
+ {
45
+ "term": "flower crown",
46
+ "type": "专用",
47
+ "subtype": "装饰 Accessory",
48
+ "chinese": "花环"
49
+ },
50
+ {
51
+ "term": "glowing bracelets",
52
+ "type": "专用",
53
+ "subtype": "装饰 Accessory",
54
+ "chinese": "发光手镯"
55
+ },
56
+ {
57
+ "term": "goggles on head",
58
+ "type": "专用",
59
+ "subtype": "装饰 Accessory",
60
+ "chinese": "头戴护目镜"
61
+ },
62
+ {
63
+ "term": "steampunk attire",
64
+ "type": "专用",
65
+ "subtype": "衣服 Clothing",
66
+ "chinese": "蒸汽朋克服饰"
67
+ },
68
+ {
69
+ "term": "elven robe",
70
+ "type": "专用",
71
+ "subtype": "衣服 Clothing",
72
+ "chinese": "精灵长袍"
73
+ },
74
+ {
75
+ "term": "celestial dress",
76
+ "type": "专用",
77
+ "subtype": "衣服 Clothing",
78
+ "chinese": "星空连衣裙"
79
+ },
80
+ {
81
+ "term": "samurai armor",
82
+ "type": "专用",
83
+ "subtype": "衣服 Clothing",
84
+ "chinese": "武士铠甲"
85
+ },
86
+ {
87
+ "term": "futuristic bodysuit",
88
+ "type": "专用",
89
+ "subtype": "衣服 Clothing",
90
+ "chinese": "未来紧身服"
91
+ },
92
+ {
93
+ "term": "historical royal gown",
94
+ "type": "专用",
95
+ "subtype": "衣服 Clothing",
96
+ "chinese": "历史宫廷礼服"
97
+ },
98
+ {
99
+ "term": "vintage detective coat",
100
+ "type": "专用",
101
+ "subtype": "衣服 Clothing",
102
+ "chinese": "复古侦探大衣"
103
+ },
104
+ {
105
+ "term": "wizard cloak",
106
+ "type": "专用",
107
+ "subtype": "衣服 Clothing",
108
+ "chinese": "巫师斗篷"
109
+ },
110
+ {
111
+ "term": "fairy tale costume",
112
+ "type": "专用",
113
+ "subtype": "衣服 Clothing",
114
+ "chinese": "童话服装"
115
+ },
116
+ {
117
+ "term": "tilting head",
118
+ "type": "专用",
119
+ "subtype": "动作 Action",
120
+ "chinese": "歪头"
121
+ },
122
+ {
123
+ "term": "smiling gently",
124
+ "type": "专用",
125
+ "subtype": "动作 Action",
126
+ "chinese": "温柔微笑"
127
+ },
128
+ {
129
+ "term": "eyes closed",
130
+ "type": "专用",
131
+ "subtype": "动作 Action",
132
+ "chinese": "闭眼"
133
+ },
134
+ {
135
+ "term": "looking up",
136
+ "type": "专用",
137
+ "subtype": "动作 Action",
138
+ "chinese": "仰望"
139
+ },
140
+ {
141
+ "term": "looking down",
142
+ "type": "专用",
143
+ "subtype": "动作 Action",
144
+ "chinese": "俯视"
145
+ },
146
+ {
147
+ "term": "blushing",
148
+ "type": "专用",
149
+ "subtype": "动作 Action",
150
+ "chinese": "脸红"
151
+ },
152
+ {
153
+ "term": "resting chin on something",
154
+ "type": "专用",
155
+ "subtype": "动作 Action",
156
+ "chinese": "下巴倚靠"
157
+ },
158
+ {
159
+ "term": "hair flowing in wind",
160
+ "type": "专用",
161
+ "subtype": "动作 Action",
162
+ "chinese": "秀发随风飘扬"
163
+ },
164
+ {
165
+ "term": "leaning back",
166
+ "type": "专用",
167
+ "subtype": "动作 Action",
168
+ "chinese": "后仰"
169
+ },
170
+ {
171
+ "term": "shoulders slightly raised",
172
+ "type": "专用",
173
+ "subtype": "动作 Action",
174
+ "chinese": "微耸双肩"
175
+ },
176
+ {
177
+ "term": "playing an instrument",
178
+ "type": "专用",
179
+ "subtype": "动作 Action",
180
+ "chinese": "演奏乐器"
181
+ },
182
+ {
183
+ "term": "exploring surroundings",
184
+ "type": "专用",
185
+ "subtype": "动作 Action",
186
+ "chinese": "探索四周"
187
+ },
188
+ {
189
+ "term": "enchanted forest",
190
+ "type": "专用",
191
+ "subtype": "场景 Scene",
192
+ "chinese": "魔法森林"
193
+ },
194
+ {
195
+ "term": "crystal cave",
196
+ "type": "专用",
197
+ "subtype": "场景 Scene",
198
+ "chinese": "水晶洞穴"
199
+ },
200
+ {
201
+ "term": "ancient ruins",
202
+ "type": "专用",
203
+ "subtype": "场景 Scene",
204
+ "chinese": "远古遗迹"
205
+ },
206
+ {
207
+ "term": "starlit meadow",
208
+ "type": "专用",
209
+ "subtype": "场景 Scene",
210
+ "chinese": "星光草原"
211
+ },
212
+ {
213
+ "term": "underwater",
214
+ "type": "专用",
215
+ "subtype": "场景 Scene",
216
+ "chinese": "水下"
217
+ },
218
+ {
219
+ "term": "autumn grove",
220
+ "type": "专用",
221
+ "subtype": "场景 Scene",
222
+ "chinese": "秋日林地"
223
+ },
224
+ {
225
+ "term": "best quality",
226
+ "type": "通用",
227
+ "chinese": "最佳质量"
228
+ },
229
+ {
230
+ "term": "game cg",
231
+ "type": "通用",
232
+ "subtype": "风格 Style",
233
+ "chinese": "游戏CG风格"
234
+ },
235
+ {
236
+ "term": "1boy",
237
+ "type": "专用",
238
+ "subtype": "主题 Subject",
239
+ "chinese": "一个男孩"
240
+ },
241
+ {
242
+ "term": "looking at viewer",
243
+ "type": "专用",
244
+ "subtype": "动作 Action",
245
+ "chinese": "看向观众"
246
+ },
247
+ {
248
+ "term": "ligne claire",
249
+ "type": "通用",
250
+ "subtype": "风格 Style",
251
+ "chinese": "清晰线条风格"
252
+ },
253
+ {
254
+ "term": "grey hair",
255
+ "type": "专用",
256
+ "subtype": "头发 Hair",
257
+ "chinese": "灰色头发"
258
+ },
259
+ {
260
+ "term": "green eyes",
261
+ "type": "专用",
262
+ "subtype": "眼睛 Eyes",
263
+ "chinese": "绿色眼睛"
264
+ },
265
+ {
266
+ "term": "animal ears",
267
+ "type": "专用",
268
+ "subtype": "装饰 Accessory",
269
+ "chinese": "动物耳朵"
270
+ },
271
+ {
272
+ "term": "cat ears",
273
+ "type": "专用",
274
+ "subtype": "装饰 Accessory",
275
+ "chinese": "猫耳"
276
+ },
277
+ {
278
+ "term": "swashbuckler costume",
279
+ "type": "专用",
280
+ "subtype": "衣服 Clothing",
281
+ "chinese": "侠客服装"
282
+ },
283
+ {
284
+ "term": "night sky",
285
+ "type": "专用",
286
+ "subtype": "场景 Scene",
287
+ "chinese": "夜空"
288
+ },
289
+ {
290
+ "term": "1girl",
291
+ "type": "专用",
292
+ "subtype": "主题 Subject",
293
+ "chinese": "一个女孩"
294
+ },
295
+ {
296
+ "term": "fantasy style",
297
+ "type": "专用",
298
+ "subtype": "风格 Style",
299
+ "chinese": "奇幻风格"
300
+ },
301
+ {
302
+ "term": "official art",
303
+ "type": "专用",
304
+ "subtype": "风格 Style",
305
+ "chinese": "官方美术风格"
306
+ },
307
+ {
308
+ "term": "baroque elegance",
309
+ "type": "专用",
310
+ "subtype": "风格 Style",
311
+ "chinese": "巴洛克优雅风格"
312
+ },
313
+ {
314
+ "term": "neo-noir lighting",
315
+ "type": "专用",
316
+ "subtype": "风格 Style",
317
+ "chinese": "新黑色电影风格"
318
+ },
319
+ {
320
+ "term": "surreal dreamscape",
321
+ "type": "专用",
322
+ "subtype": "风格 Style",
323
+ "chinese": "超现实梦境风格"
324
+ },
325
+ {
326
+ "term": "gothic romance",
327
+ "type": "专用",
328
+ "subtype": "风格 Style",
329
+ "chinese": "哥特浪漫风格"
330
+ },
331
+ {
332
+ "term": "celestial fantasy",
333
+ "type": "专用",
334
+ "subtype": "风格 Style",
335
+ "chinese": "天体奇幻风格"
336
+ },
337
+ {
338
+ "term": "bioluminescent night",
339
+ "type": "专用",
340
+ "subtype": "风格 Style",
341
+ "chinese": "生物发光夜景风格"
342
+ },
343
+ {
344
+ "term": "arcane vintage",
345
+ "type": "专用",
346
+ "subtype": "风格 Style",
347
+ "chinese": "神秘复古风格"
348
+ },
349
+ {
350
+ "term": "storybook illustration",
351
+ "type": "专用",
352
+ "subtype": "风格 Style",
353
+ "chinese": "童话书插画风格"
354
+ },
355
+ {
356
+ "term": "ethereal watercolor",
357
+ "type": "专用",
358
+ "subtype": "风格 Style",
359
+ "chinese": "空灵水彩画风"
360
+ },
361
+ {
362
+ "term": "futuristic abstraction",
363
+ "type": "专用",
364
+ "subtype": "风格 Style",
365
+ "chinese": "未来抽象风格"
366
+ },
367
+ {
368
+ "term": "4k textures",
369
+ "type": "通用",
370
+ "subtype": "quality",
371
+ "chinese": "4K纹理"
372
+ },
373
+ {
374
+ "term": "black hair",
375
+ "type": "专用",
376
+ "subtype": "头发 Hair",
377
+ "chinese": "黑发"
378
+ },
379
+ {
380
+ "term": "detailed feathers",
381
+ "type": "专用",
382
+ "subtype": "装饰 Accessory",
383
+ "chinese": "精细羽毛"
384
+ },
385
+ {
386
+ "term": "aggressive pose",
387
+ "type": "专用",
388
+ "subtype": "动作 Action",
389
+ "chinese": "攻击性姿势"
390
+ },
391
+ {
392
+ "term": "midflight",
393
+ "type": "专用",
394
+ "subtype": "动作 Action",
395
+ "chinese": "飞行中"
396
+ },
397
+ {
398
+ "term": "glowing effects",
399
+ "type": "专用",
400
+ "subtype": "场景 Scene",
401
+ "chinese": "发光特效"
402
+ },
403
+ {
404
+ "term": "dark background",
405
+ "type": "专用",
406
+ "subtype": "场景 Scene",
407
+ "chinese": "暗色背景"
408
+ },
409
+ {
410
+ "term": "fire",
411
+ "type": "专用",
412
+ "subtype": "场景 Scene",
413
+ "chinese": "火焰"
414
+ },
415
+ {
416
+ "term": "dramatic lighting",
417
+ "type": "通用",
418
+ "subtype": "lighting",
419
+ "chinese": "戏剧性打光"
420
+ },
421
+ {
422
+ "term": "sharp focus",
423
+ "type": "通用",
424
+ "subtype": "quality",
425
+ "chinese": "锐利焦点"
426
+ },
427
+ {
428
+ "term": "epic scenery",
429
+ "type": "专用",
430
+ "subtype": "场景 Scene",
431
+ "chinese": "史诗级场景"
432
+ },
433
+ {
434
+ "term": "hdr",
435
+ "type": "通用",
436
+ "subtype": "quality",
437
+ "chinese": "高动态范围"
438
+ },
439
+ {
440
+ "term": "movie still",
441
+ "type": "通用",
442
+ "subtype": "风格 Style",
443
+ "chinese": "电影剧照风格"
444
+ },
445
+ {
446
+ "term": "depth of field",
447
+ "type": "通用",
448
+ "subtype": "photography",
449
+ "chinese": "景深效果"
450
+ },
451
+ {
452
+ "term": "anime coloring",
453
+ "type": "通用",
454
+ "subtype": "风格 Style",
455
+ "chinese": "动漫上色风格"
456
+ },
457
+ {
458
+ "term": "blonde hair",
459
+ "type": "专用",
460
+ "subtype": "头发 Hair",
461
+ "chinese": "金发"
462
+ },
463
+ {
464
+ "term": "yellow eyes",
465
+ "type": "专用",
466
+ "subtype": "眼睛 Eyes",
467
+ "chinese": "黄瞳"
468
+ },
469
+ {
470
+ "term": "multicolored hair",
471
+ "type": "专用",
472
+ "subtype": "头发 Hair",
473
+ "chinese": "多色头发"
474
+ },
475
+ {
476
+ "term": "two-tone hair",
477
+ "type": "专用",
478
+ "subtype": "头发 Hair",
479
+ "chinese": "双色渐变发"
480
+ },
481
+ {
482
+ "term": "jewelry",
483
+ "type": "专用",
484
+ "subtype": "装饰 Accessory",
485
+ "chinese": "珠宝饰品"
486
+ },
487
+ {
488
+ "term": "butler costume",
489
+ "type": "专用",
490
+ "subtype": "衣服 Clothing",
491
+ "chinese": "管家服饰"
492
+ },
493
+ {
494
+ "term": "world war 1",
495
+ "type": "专用",
496
+ "subtype": "场景 Scene",
497
+ "chinese": "一战背景"
498
+ },
499
+ {
500
+ "term": "High resolution",
501
+ "type": "通用",
502
+ "subtype": "quality",
503
+ "chinese": "高清分辨率"
504
+ },
505
+ {
506
+ "term": "photorealistic",
507
+ "type": "通用",
508
+ "subtype": "风格 Style",
509
+ "chinese": "照片级写实"
510
+ },
511
+ {
512
+ "term": "4k",
513
+ "type": "通用",
514
+ "subtype": "quality",
515
+ "chinese": "4K超清"
516
+ },
517
+ {
518
+ "term": "Masterpiece",
519
+ "type": "通用",
520
+ "chinese": "大师级作品"
521
+ },
522
+ {
523
+ "term": "extremely detailed",
524
+ "type": "通用",
525
+ "subtype": "quality",
526
+ "chinese": "极致细节"
527
+ },
528
+ {
529
+ "term": "professional photography",
530
+ "type": "通用",
531
+ "subtype": "风格 Style",
532
+ "chinese": "专业摄影质感"
533
+ },
534
+ {
535
+ "term": "sharp detail",
536
+ "type": "通用",
537
+ "subtype": "quality",
538
+ "chinese": "锐利细节"
539
+ },
540
+ {
541
+ "term": "grey eyes",
542
+ "type": "专用",
543
+ "subtype": "眼睛 Eyes",
544
+ "chinese": "灰眸"
545
+ },
546
+ {
547
+ "term": "earrings",
548
+ "type": "专用",
549
+ "subtype": "装饰 Accessory",
550
+ "chinese": "耳环饰品"
551
+ },
552
+ {
553
+ "term": "cloche hat",
554
+ "type": "专用",
555
+ "subtype": "装饰 Accessory",
556
+ "chinese": "钟形女帽"
557
+ },
558
+ {
559
+ "term": "steampunk",
560
+ "type": "专用",
561
+ "subtype": "风格 Style",
562
+ "chinese": "蒸汽朋克主题"
563
+ },
564
+ {
565
+ "term": "intricate details",
566
+ "type": "通用",
567
+ "subtype": "quality",
568
+ "chinese": "复杂细节"
569
+ },
570
+ {
571
+ "term": "unity 8k wallpaper",
572
+ "type": "通用",
573
+ "subtype": "风格 Style",
574
+ "chinese": "Unity引擎8K壁纸风格"
575
+ },
576
+ {
577
+ "term": "ultra detailed",
578
+ "type": "通用",
579
+ "subtype": "quality",
580
+ "chinese": "超精细细节"
581
+ },
582
+ {
583
+ "term": "beautiful and aesthetic",
584
+ "type": "通用",
585
+ "subtype": "风格 Style",
586
+ "chinese": "唯美艺术风格"
587
+ },
588
+ {
589
+ "term": "perfect lighting",
590
+ "type": "通用",
591
+ "subtype": "photography",
592
+ "chinese": "完美布光"
593
+ },
594
+ {
595
+ "term": "gradient coloured hair",
596
+ "type": "专用",
597
+ "subtype": "头发 Hair",
598
+ "chinese": "渐变色发型"
599
+ },
600
+ {
601
+ "term": "sfw",
602
+ "type": "通用",
603
+ "subtype": "safety",
604
+ "chinese": "安全内容过滤"
605
+ },
606
+ {
607
+ "term": "expressionless",
608
+ "type": "专用",
609
+ "subtype": "动作 Action",
610
+ "chinese": "无表情状态"
611
+ },
612
+ {
613
+ "term": "formal",
614
+ "type": "专用",
615
+ "subtype": "衣服 Clothing",
616
+ "chinese": "正式着装"
617
+ },
618
+ {
619
+ "term": "necktie",
620
+ "type": "专用",
621
+ "subtype": "装饰 Accessory",
622
+ "chinese": "领带"
623
+ },
624
+ {
625
+ "term": "dress shirt",
626
+ "type": "专用",
627
+ "subtype": "衣服 Clothing",
628
+ "chinese": "衬衫"
629
+ },
630
+ {
631
+ "term": "ray tracing",
632
+ "type": "通用",
633
+ "subtype": "photography",
634
+ "chinese": "光线追踪技术"
635
+ },
636
+ {
637
+ "term": "Heavenly Cathedral",
638
+ "type": "专用",
639
+ "subtype": "场景 Scene",
640
+ "chinese": "天界大教堂场景"
641
+ },
642
+ {
643
+ "term": "monk",
644
+ "type": "专用",
645
+ "subtype": "衣服 Clothing",
646
+ "chinese": "僧侣服饰"
647
+ },
648
+ {
649
+ "term": "diablo style",
650
+ "type": "专用",
651
+ "subtype": "风格 Style",
652
+ "chinese": "暗黑破坏神风格"
653
+ },
654
+ {
655
+ "term": "ultra realistic 8k",
656
+ "type": "通用",
657
+ "subtype": "quality",
658
+ "chinese": "8K超现实精度"
659
+ },
660
+ {
661
+ "term": "cinematic lighting",
662
+ "type": "通用",
663
+ "subtype": "photography",
664
+ "chinese": "电影级布光"
665
+ },
666
+ {
667
+ "term": "hyperdetailed",
668
+ "type": "通用",
669
+ "subtype": "quality",
670
+ "chinese": "超解析细节"
671
+ },
672
+ {
673
+ "term": "neutral colors",
674
+ "type": "通用",
675
+ "subtype": "color",
676
+ "chinese": "中性色调"
677
+ },
678
+ {
679
+ "term": "muted colors",
680
+ "type": "通用",
681
+ "subtype": "color",
682
+ "chinese": "低饱和配色"
683
+ },
684
+ {
685
+ "term": "fine texture",
686
+ "type": "通用",
687
+ "subtype": "quality",
688
+ "chinese": "精细材质纹理"
689
+ },
690
+ {
691
+ "term": "highly detailed",
692
+ "type": "通用",
693
+ "chinese": "高度细节"
694
+ },
695
+ {
696
+ "term": "absurdres",
697
+ "type": "通用",
698
+ "chinese": "超高分辨率"
699
+ },
700
+ {
701
+ "term": "low light",
702
+ "type": "通用",
703
+ "chinese": "低光环境"
704
+ },
705
+ {
706
+ "term": "partially illuminated",
707
+ "type": "通用",
708
+ "chinese": "局部照明"
709
+ },
710
+ {
711
+ "term": "bokeh",
712
+ "type": "通用",
713
+ "chinese": "散景效果"
714
+ },
715
+ {
716
+ "term": "cinematic environment",
717
+ "type": "通用",
718
+ "chinese": "电影级环境"
719
+ },
720
+ {
721
+ "term": "volumetric lighting",
722
+ "type": "通用",
723
+ "chinese": "体积光照"
724
+ },
725
+ {
726
+ "term": "hazy background",
727
+ "type": "通用",
728
+ "chinese": "朦胧背景"
729
+ },
730
+ {
731
+ "term": "high detail",
732
+ "type": "通用",
733
+ "chinese": "高细节度"
734
+ },
735
+ {
736
+ "term": "immersive atmosphere",
737
+ "type": "通用",
738
+ "chinese": "沉浸式氛围"
739
+ },
740
+ {
741
+ "term": "intricate texture",
742
+ "type": "通用",
743
+ "chinese": "复杂纹理"
744
+ },
745
+ {
746
+ "term": "blue eyeshadow",
747
+ "type": "专用",
748
+ "subtype": "眼睛 Eyes",
749
+ "chinese": "蓝色眼影"
750
+ },
751
+ {
752
+ "term": "black coat",
753
+ "type": "专用",
754
+ "subtype": "衣服 Clothing",
755
+ "chinese": "黑色外套"
756
+ },
757
+ {
758
+ "term": "windblown hair",
759
+ "type": "专用",
760
+ "subtype": "头发 Hair",
761
+ "chinese": "风扬发型"
762
+ },
763
+ {
764
+ "term": "white hair",
765
+ "type": "专用",
766
+ "subtype": "头发 Hair",
767
+ "chinese": "白色头发"
768
+ },
769
+ {
770
+ "term": "glowing hair",
771
+ "type": "专用",
772
+ "subtype": "头发 Hair",
773
+ "chinese": "发光发丝"
774
+ },
775
+ {
776
+ "term": "iridescent hair",
777
+ "type": "专用",
778
+ "subtype": "头发 Hair",
779
+ "chinese": "虹彩发色"
780
+ },
781
+ {
782
+ "term": "gradient hair",
783
+ "type": "专用",
784
+ "subtype": "头发 Hair",
785
+ "chinese": "渐变发色"
786
+ },
787
+ {
788
+ "term": "glowing yellow eye",
789
+ "type": "专用",
790
+ "subtype": "眼睛 Eyes",
791
+ "chinese": "发光黄瞳"
792
+ },
793
+ {
794
+ "term": "fiberoptic hair",
795
+ "type": "专用",
796
+ "subtype": "头发 Hair",
797
+ "chinese": "光纤头发"
798
+ },
799
+ {
800
+ "term": "flaming hair",
801
+ "type": "专用",
802
+ "subtype": "头发 Hair",
803
+ "chinese": "火焰发型"
804
+ },
805
+ {
806
+ "term": "perfect details",
807
+ "type": "通用",
808
+ "chinese": "完美细节"
809
+ },
810
+ {
811
+ "term": "illustration",
812
+ "type": "通用",
813
+ "chinese": "插画风格"
814
+ },
815
+ {
816
+ "term": "glasses",
817
+ "type": "专用",
818
+ "subtype": "装饰 Accessory",
819
+ "chinese": "眼镜"
820
+ },
821
+ {
822
+ "term": "shirt",
823
+ "type": "专用",
824
+ "subtype": "衣服 Clothing",
825
+ "chinese": "衬衫"
826
+ },
827
+ {
828
+ "term": "hood",
829
+ "type": "专用",
830
+ "subtype": "衣服 Clothing",
831
+ "chinese": "兜帽"
832
+ },
833
+ {
834
+ "term": "jacket",
835
+ "type": "专用",
836
+ "subtype": "衣服 Clothing",
837
+ "chinese": "夹克"
838
+ },
839
+ {
840
+ "term": "red shirt",
841
+ "type": "专用",
842
+ "subtype": "衣服 Clothing",
843
+ "chinese": "红色衬衫"
844
+ },
845
+ {
846
+ "term": "cloud",
847
+ "type": "专用",
848
+ "subtype": "场景 Scene",
849
+ "chinese": "云朵"
850
+ },
851
+ {
852
+ "term": "black-framed eyewear",
853
+ "type": "专用",
854
+ "subtype": "装饰 Accessory",
855
+ "chinese": "黑框眼镜"
856
+ },
857
+ {
858
+ "term": "long sleeves",
859
+ "type": "专用",
860
+ "subtype": "衣服 Clothing",
861
+ "chinese": "长袖"
862
+ },
863
+ {
864
+ "term": "sky",
865
+ "type": "专用",
866
+ "subtype": "场景 Scene",
867
+ "chinese": "天空"
868
+ },
869
+ {
870
+ "term": "hair between eyes",
871
+ "type": "专用",
872
+ "subtype": "头发 Hair",
873
+ "chinese": "遮眼发型"
874
+ },
875
+ {
876
+ "term": "closed mouth",
877
+ "type": "专用",
878
+ "subtype": "动作 Action",
879
+ "chinese": "闭口"
880
+ },
881
+ {
882
+ "term": "outdoors",
883
+ "type": "专用",
884
+ "subtype": "场景 Scene",
885
+ "chinese": "户外"
886
+ },
887
+ {
888
+ "term": "black jacket",
889
+ "type": "专用",
890
+ "subtype": "衣服 Clothing",
891
+ "chinese": "黑色夹克"
892
+ },
893
+ {
894
+ "term": "short hair",
895
+ "type": "专用",
896
+ "subtype": "头发 Hair",
897
+ "chinese": "短发"
898
+ },
899
+ {
900
+ "term": "hood down",
901
+ "type": "专用",
902
+ "subtype": "衣服 Clothing",
903
+ "chinese": "放下兜帽"
904
+ },
905
+ {
906
+ "term": "sunset",
907
+ "type": "专用",
908
+ "subtype": "场景 Scene",
909
+ "chinese": "日落"
910
+ },
911
+ {
912
+ "term": "hooded jacket",
913
+ "type": "专用",
914
+ "subtype": "衣服 Clothing",
915
+ "chinese": "连帽夹克"
916
+ },
917
+ {
918
+ "term": "hoodie",
919
+ "type": "专用",
920
+ "subtype": "衣服 Clothing",
921
+ "chinese": "连帽衫"
922
+ },
923
+ {
924
+ "term": "sleeves past wrists",
925
+ "type": "专用",
926
+ "subtype": "衣服 Clothing",
927
+ "chinese": "过腕长袖"
928
+ },
929
+ {
930
+ "term": "open jacket",
931
+ "type": "专用",
932
+ "subtype": "衣服 Clothing",
933
+ "chinese": "敞开夹克"
934
+ },
935
+ {
936
+ "term": "dynamic angle",
937
+ "type": "通用",
938
+ "chinese": "动态视角"
939
+ },
940
+ {
941
+ "term": "ultra-detailed",
942
+ "type": "通用",
943
+ "chinese": "超精细细节"
944
+ },
945
+ {
946
+ "term": "fantasy",
947
+ "type": "专用",
948
+ "subtype": "风格 Style",
949
+ "chinese": "奇幻主题"
950
+ },
951
+ {
952
+ "term": "beautiful and detailed eyes",
953
+ "type": "专用",
954
+ "subtype": "眼睛 Eyes",
955
+ "chinese": "精美细致眼瞳"
956
+ },
957
+ {
958
+ "term": "long straight hair",
959
+ "type": "专用",
960
+ "subtype": "头发 Hair",
961
+ "chinese": "直长发"
962
+ },
963
+ {
964
+ "term": "hair flower",
965
+ "type": "专用",
966
+ "subtype": "装饰 Accessory",
967
+ "chinese": "发间花朵饰品"
968
+ },
969
+ {
970
+ "term": "japanese long kimono with flowers",
971
+ "type": "专用",
972
+ "subtype": "衣服 Clothing",
973
+ "chinese": "花卉日式长振袖"
974
+ },
975
+ {
976
+ "term": "detached sleeves",
977
+ "type": "专用",
978
+ "subtype": "衣服 Clothing",
979
+ "chinese": "离脱式袖套"
980
+ },
981
+ {
982
+ "term": "wide sleeves",
983
+ "type": "专用",
984
+ "subtype": "衣服 Clothing",
985
+ "chinese": "广口衣袖"
986
+ },
987
+ {
988
+ "term": "stockings",
989
+ "type": "专用",
990
+ "subtype": "衣服 Clothing",
991
+ "chinese": "长筒袜"
992
+ },
993
+ {
994
+ "term": "detail fingers",
995
+ "type": "通用",
996
+ "chinese": "精细手指描绘"
997
+ },
998
+ {
999
+ "term": "magic dark forest background",
1000
+ "type": "专用",
1001
+ "subtype": "场景 Scene",
1002
+ "chinese": "魔法暗黑森林背景"
1003
+ },
1004
+ {
1005
+ "term": "anime",
1006
+ "type": "通用",
1007
+ "chinese": "动漫风格"
1008
+ },
1009
+ {
1010
+ "term": "2d",
1011
+ "type": "通用",
1012
+ "chinese": "二维平面"
1013
+ },
1014
+ {
1015
+ "term": "ghibli style",
1016
+ "type": "通用",
1017
+ "chinese": "吉卜力画风"
1018
+ },
1019
+ {
1020
+ "term": "white fox tail",
1021
+ "type": "专用",
1022
+ "subtype": "装饰 Accessory",
1023
+ "chinese": "白狐尾巴"
1024
+ },
1025
+ {
1026
+ "term": "black pantyhose",
1027
+ "type": "专用",
1028
+ "subtype": "衣服 Clothing",
1029
+ "chinese": "黑色连裤袜"
1030
+ },
1031
+ {
1032
+ "term": "blue eyes",
1033
+ "type": "专用",
1034
+ "subtype": "眼睛 Eyes",
1035
+ "chinese": "蓝色眼睛"
1036
+ }
1037
+ ]
1038
+ }
client_jp/person_jp.json ADDED
@@ -0,0 +1,1214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "prompt_terms": [
3
+ {
4
+ "term": "masterpiece",
5
+ "type": "通用",
6
+ "chinese": "杰作级别",
7
+ "japanese": "傑作"
8
+ },
9
+ {
10
+ "term": "fox tail",
11
+ "type": "专用",
12
+ "subtype": "アクセサリー Accessory",
13
+ "chinese": "狐狸尾巴",
14
+ "japanese": "キツネの尾"
15
+ },
16
+ {
17
+ "term": "crystal tiara",
18
+ "type": "专用",
19
+ "subtype": "アクセサリー Accessory",
20
+ "chinese": "水晶王冠",
21
+ "japanese": "クリスタルティアラ"
22
+ },
23
+ {
24
+ "term": "feather hairpin",
25
+ "type": "专用",
26
+ "subtype": "アクセサリー Accessory",
27
+ "chinese": "羽毛发夹",
28
+ "japanese": "フェザーヘアピン"
29
+ },
30
+ {
31
+ "term": "butterfly wings",
32
+ "type": "专用",
33
+ "subtype": "アクセサリー Accessory",
34
+ "chinese": "蝴蝶翅膀",
35
+ "japanese": "蝶の翼"
36
+ },
37
+ {
38
+ "term": "star-shaped earrings",
39
+ "type": "专用",
40
+ "subtype": "アクセサリー Accessory",
41
+ "chinese": "星星耳饰",
42
+ "japanese": "星型のイヤリング"
43
+ },
44
+ {
45
+ "term": "ribbon choker",
46
+ "type": "专用",
47
+ "subtype": "アクセサリー Accessory",
48
+ "chinese": "缎带项圈",
49
+ "japanese": "リボンチョーカー"
50
+ },
51
+ {
52
+ "term": "flower crown",
53
+ "type": "专用",
54
+ "subtype": "アクセサリー Accessory",
55
+ "chinese": "花环",
56
+ "japanese": "フラワークラウン"
57
+ },
58
+ {
59
+ "term": "glowing bracelets",
60
+ "type": "专用",
61
+ "subtype": "アクセサリー Accessory",
62
+ "chinese": "发光手镯",
63
+ "japanese": "輝くブレスレット"
64
+ },
65
+ {
66
+ "term": "goggles on head",
67
+ "type": "专用",
68
+ "subtype": "アクセサリー Accessory",
69
+ "chinese": "头戴护目镜",
70
+ "japanese": "頭のゴーグル"
71
+ },
72
+ {
73
+ "term": "steampunk attire",
74
+ "type": "专用",
75
+ "subtype": "衣類 Clothing",
76
+ "chinese": "蒸汽朋克服饰",
77
+ "japanese": "スチームパンクの服装"
78
+ },
79
+ {
80
+ "term": "elven robe",
81
+ "type": "专用",
82
+ "subtype": "衣類 Clothing",
83
+ "chinese": "精灵长袍",
84
+ "japanese": "エルフローブ"
85
+ },
86
+ {
87
+ "term": "celestial dress",
88
+ "type": "专用",
89
+ "subtype": "衣類 Clothing",
90
+ "chinese": "星空连衣裙",
91
+ "japanese": "天のドレス"
92
+ },
93
+ {
94
+ "term": "samurai armor",
95
+ "type": "专用",
96
+ "subtype": "衣類 Clothing",
97
+ "chinese": "武士铠甲",
98
+ "japanese": "サムライアーマー"
99
+ },
100
+ {
101
+ "term": "futuristic bodysuit",
102
+ "type": "专用",
103
+ "subtype": "衣類 Clothing",
104
+ "chinese": "未来紧身服",
105
+ "japanese": "未来のボディスーツ"
106
+ },
107
+ {
108
+ "term": "historical royal gown",
109
+ "type": "专用",
110
+ "subtype": "衣類 Clothing",
111
+ "chinese": "历史宫廷礼服",
112
+ "japanese": "歴史的なロイヤルガウン"
113
+ },
114
+ {
115
+ "term": "vintage detective coat",
116
+ "type": "专用",
117
+ "subtype": "衣類 Clothing",
118
+ "chinese": "复古侦探大衣",
119
+ "japanese": "ヴィンテージ探偵コート"
120
+ },
121
+ {
122
+ "term": "wizard cloak",
123
+ "type": "专用",
124
+ "subtype": "衣類 Clothing",
125
+ "chinese": "巫师斗篷",
126
+ "japanese": "ウィザードマント"
127
+ },
128
+ {
129
+ "term": "fairy tale costume",
130
+ "type": "专用",
131
+ "subtype": "衣類 Clothing",
132
+ "chinese": "童话服装",
133
+ "japanese": "おとぎ話の衣装"
134
+ },
135
+ {
136
+ "term": "tilting head",
137
+ "type": "专用",
138
+ "subtype": "アクション Action",
139
+ "chinese": "歪头",
140
+ "japanese": "傾きヘッド"
141
+ },
142
+ {
143
+ "term": "smiling gently",
144
+ "type": "专用",
145
+ "subtype": "アクション Action",
146
+ "chinese": "温柔微笑",
147
+ "japanese": "優しく笑っています"
148
+ },
149
+ {
150
+ "term": "eyes closed",
151
+ "type": "专用",
152
+ "subtype": "アクション Action",
153
+ "chinese": "闭眼",
154
+ "japanese": "目を閉じた"
155
+ },
156
+ {
157
+ "term": "looking up",
158
+ "type": "专用",
159
+ "subtype": "アクション Action",
160
+ "chinese": "仰望",
161
+ "japanese": "見上げる"
162
+ },
163
+ {
164
+ "term": "looking down",
165
+ "type": "专用",
166
+ "subtype": "アクション Action",
167
+ "chinese": "俯视",
168
+ "japanese": "見下ろす"
169
+ },
170
+ {
171
+ "term": "blushing",
172
+ "type": "专用",
173
+ "subtype": "アクション Action",
174
+ "chinese": "脸红",
175
+ "japanese": "赤面"
176
+ },
177
+ {
178
+ "term": "resting chin on something",
179
+ "type": "专用",
180
+ "subtype": "アクション Action",
181
+ "chinese": "下巴倚靠",
182
+ "japanese": "何かにあごを置く"
183
+ },
184
+ {
185
+ "term": "hair flowing in wind",
186
+ "type": "专用",
187
+ "subtype": "アク���ョン Action",
188
+ "chinese": "秀发随风飘扬",
189
+ "japanese": "風に流れる髪"
190
+ },
191
+ {
192
+ "term": "leaning back",
193
+ "type": "专用",
194
+ "subtype": "アクション Action",
195
+ "chinese": "后仰",
196
+ "japanese": "後ろに傾いています"
197
+ },
198
+ {
199
+ "term": "shoulders slightly raised",
200
+ "type": "专用",
201
+ "subtype": "アクション Action",
202
+ "chinese": "微耸双肩",
203
+ "japanese": "肩がわずかに上昇しました"
204
+ },
205
+ {
206
+ "term": "playing an instrument",
207
+ "type": "专用",
208
+ "subtype": "アクション Action",
209
+ "chinese": "演奏乐器",
210
+ "japanese": "楽器を演奏します"
211
+ },
212
+ {
213
+ "term": "exploring surroundings",
214
+ "type": "专用",
215
+ "subtype": "アクション Action",
216
+ "chinese": "探索四周",
217
+ "japanese": "周囲を探索します"
218
+ },
219
+ {
220
+ "term": "enchanted forest",
221
+ "type": "专用",
222
+ "subtype": "シーン Scene",
223
+ "chinese": "魔法森林",
224
+ "japanese": "魅惑的な森"
225
+ },
226
+ {
227
+ "term": "crystal cave",
228
+ "type": "专用",
229
+ "subtype": "シーン Scene",
230
+ "chinese": "水晶洞穴",
231
+ "japanese": "クリスタル洞窟"
232
+ },
233
+ {
234
+ "term": "ancient ruins",
235
+ "type": "专用",
236
+ "subtype": "シーン Scene",
237
+ "chinese": "远古遗迹",
238
+ "japanese": "古代の遺跡"
239
+ },
240
+ {
241
+ "term": "starlit meadow",
242
+ "type": "专用",
243
+ "subtype": "シーン Scene",
244
+ "chinese": "星光草原",
245
+ "japanese": "スターライトメドウ"
246
+ },
247
+ {
248
+ "term": "underwater",
249
+ "type": "专用",
250
+ "subtype": "シーン Scene",
251
+ "chinese": "水下",
252
+ "japanese": "水中"
253
+ },
254
+ {
255
+ "term": "autumn grove",
256
+ "type": "专用",
257
+ "subtype": "シーン Scene",
258
+ "chinese": "秋日林地",
259
+ "japanese": "秋の木立"
260
+ },
261
+ {
262
+ "term": "best quality",
263
+ "type": "通用",
264
+ "chinese": "最佳质量",
265
+ "japanese": "最高品質"
266
+ },
267
+ {
268
+ "term": "game cg",
269
+ "type": "通用",
270
+ "subtype": "スタイル Style",
271
+ "chinese": "游戏CG风格",
272
+ "japanese": "ゲームCG"
273
+ },
274
+ {
275
+ "term": "1boy",
276
+ "type": "专用",
277
+ "subtype": "テーマ Subject",
278
+ "chinese": "一个男孩",
279
+ "japanese": "1boy"
280
+ },
281
+ {
282
+ "term": "looking at viewer",
283
+ "type": "专用",
284
+ "subtype": "アクション Action",
285
+ "chinese": "看向观众",
286
+ "japanese": "視聴者を見ています"
287
+ },
288
+ {
289
+ "term": "ligne claire",
290
+ "type": "通用",
291
+ "subtype": "スタイル Style",
292
+ "chinese": "清晰线条风格",
293
+ "japanese": "リグー・クレア"
294
+ },
295
+ {
296
+ "term": "grey hair",
297
+ "type": "专用",
298
+ "subtype": "髪 Hair",
299
+ "chinese": "灰色头发",
300
+ "japanese": "白髪"
301
+ },
302
+ {
303
+ "term": "green eyes",
304
+ "type": "专用",
305
+ "subtype": "目 Eyes",
306
+ "chinese": "绿色眼睛",
307
+ "japanese": "緑の目"
308
+ },
309
+ {
310
+ "term": "animal ears",
311
+ "type": "专用",
312
+ "subtype": "アクセサリー Accessory",
313
+ "chinese": "动物耳朵",
314
+ "japanese": "動物の耳"
315
+ },
316
+ {
317
+ "term": "cat ears",
318
+ "type": "专用",
319
+ "subtype": "アクセサリー Accessory",
320
+ "chinese": "猫耳",
321
+ "japanese": "猫の耳"
322
+ },
323
+ {
324
+ "term": "swashbuckler costume",
325
+ "type": "专用",
326
+ "subtype": "衣類 Clothing",
327
+ "chinese": "侠客服装",
328
+ "japanese": "スワッシュバックラーの衣装"
329
+ },
330
+ {
331
+ "term": "night sky",
332
+ "type": "专用",
333
+ "subtype": "シーン Scene",
334
+ "chinese": "夜空",
335
+ "japanese": "夜空"
336
+ },
337
+ {
338
+ "term": "1girl",
339
+ "type": "专用",
340
+ "subtype": "テーマ Subject",
341
+ "chinese": "一个女孩",
342
+ "japanese": "1ガール"
343
+ },
344
+ {
345
+ "term": "fantasy style",
346
+ "type": "专用",
347
+ "subtype": "スタイル Style",
348
+ "chinese": "奇幻风格",
349
+ "japanese": "ファンタジースタイル"
350
+ },
351
+ {
352
+ "term": "official art",
353
+ "type": "专用",
354
+ "subtype": "スタイル Style",
355
+ "chinese": "官方美术风格",
356
+ "japanese": "公式アート"
357
+ },
358
+ {
359
+ "term": "baroque elegance",
360
+ "type": "专用",
361
+ "subtype": "スタイル Style",
362
+ "chinese": "巴洛克优雅风格",
363
+ "japanese": "バロックの優雅さ"
364
+ },
365
+ {
366
+ "term": "neo-noir lighting",
367
+ "type": "专用",
368
+ "subtype": "スタイル Style",
369
+ "chinese": "新黑色电影风格",
370
+ "japanese": "ネオノワール照明"
371
+ },
372
+ {
373
+ "term": "surreal dreamscape",
374
+ "type": "专用",
375
+ "subtype": "スタイル Style",
376
+ "chinese": "超现实梦境风格",
377
+ "japanese": "超現実的な夢のようなスケープ"
378
+ },
379
+ {
380
+ "term": "gothic romance",
381
+ "type": "专用",
382
+ "subtype": "スタイル Style",
383
+ "chinese": "哥特浪漫风格",
384
+ "japanese": "ゴシックロマンス"
385
+ },
386
+ {
387
+ "term": "celestial fantasy",
388
+ "type": "专用",
389
+ "subtype": "スタイル Style",
390
+ "chinese": "天体奇幻风格",
391
+ "japanese": "天のファンタジー"
392
+ },
393
+ {
394
+ "term": "bioluminescent night",
395
+ "type": "专用",
396
+ "subtype": "スタイル Style",
397
+ "chinese": "生物发光夜景风格",
398
+ "japanese": "生物発光の夜"
399
+ },
400
+ {
401
+ "term": "arcane vintage",
402
+ "type": "专用",
403
+ "subtype": "スタイル Style",
404
+ "chinese": "神秘复古风格",
405
+ "japanese": "アーケインヴィンテージ"
406
+ },
407
+ {
408
+ "term": "storybook illustration",
409
+ "type": "专用",
410
+ "subtype": "スタイル Style",
411
+ "chinese": "童话书插画风格",
412
+ "japanese": "ストーリーブックのイラスト"
413
+ },
414
+ {
415
+ "term": "ethereal watercolor",
416
+ "type": "专用",
417
+ "subtype": "スタイル Style",
418
+ "chinese": "空灵水彩画风",
419
+ "japanese": "エーテルの水彩画"
420
+ },
421
+ {
422
+ "term": "futuristic abstraction",
423
+ "type": "专用",
424
+ "subtype": "スタイル Style",
425
+ "chinese": "未来抽象风格",
426
+ "japanese": "未来の抽象化"
427
+ },
428
+ {
429
+ "term": "4k textures",
430
+ "type": "通用",
431
+ "subtype": "quality",
432
+ "chinese": "4K纹理",
433
+ "japanese": "4Kテクスチャ"
434
+ },
435
+ {
436
+ "term": "black hair",
437
+ "type": "专用",
438
+ "subtype": "髪 Hair",
439
+ "chinese": "黑发",
440
+ "japanese": "黒髪"
441
+ },
442
+ {
443
+ "term": "detailed feathers",
444
+ "type": "专用",
445
+ "subtype": "アクセサリー Accessory",
446
+ "chinese": "精细羽毛",
447
+ "japanese": "詳細な羽"
448
+ },
449
+ {
450
+ "term": "aggressive pose",
451
+ "type": "专用",
452
+ "subtype": "アクション Action",
453
+ "chinese": "攻击性姿势",
454
+ "japanese": "攻撃的なポーズ"
455
+ },
456
+ {
457
+ "term": "midflight",
458
+ "type": "专用",
459
+ "subtype": "アクション Action",
460
+ "chinese": "飞行中",
461
+ "japanese": "ミッドフライト"
462
+ },
463
+ {
464
+ "term": "glowing effects",
465
+ "type": "专用",
466
+ "subtype": "シーン Scene",
467
+ "chinese": "发光特效",
468
+ "japanese": "輝く効果"
469
+ },
470
+ {
471
+ "term": "dark background",
472
+ "type": "专用",
473
+ "subtype": "シーン Scene",
474
+ "chinese": "暗色背景",
475
+ "japanese": "暗い背景"
476
+ },
477
+ {
478
+ "term": "fire",
479
+ "type": "专用",
480
+ "subtype": "シーン Scene",
481
+ "chinese": "火焰",
482
+ "japanese": "火"
483
+ },
484
+ {
485
+ "term": "dramatic lighting",
486
+ "type": "通用",
487
+ "subtype": "lighting",
488
+ "chinese": "戏剧性打光",
489
+ "japanese": "劇的な照明"
490
+ },
491
+ {
492
+ "term": "sharp focus",
493
+ "type": "通用",
494
+ "subtype": "quality",
495
+ "chinese": "锐利焦点",
496
+ "japanese": "シャープな焦点"
497
+ },
498
+ {
499
+ "term": "epic scenery",
500
+ "type": "专用",
501
+ "subtype": "シーン Scene",
502
+ "chinese": "史诗级场景",
503
+ "japanese": "壮大な景色"
504
+ },
505
+ {
506
+ "term": "hdr",
507
+ "type": "通用",
508
+ "subtype": "quality",
509
+ "chinese": "高动态范围",
510
+ "japanese": "HDR"
511
+ },
512
+ {
513
+ "term": "movie still",
514
+ "type": "通用",
515
+ "subtype": "スタイル Style",
516
+ "chinese": "电影剧照风格",
517
+ "japanese": "まだ映画"
518
+ },
519
+ {
520
+ "term": "depth of field",
521
+ "type": "通用",
522
+ "subtype": "photography",
523
+ "chinese": "景深效果",
524
+ "japanese": "被写界深度"
525
+ },
526
+ {
527
+ "term": "anime coloring",
528
+ "type": "通用",
529
+ "subtype": "スタイル Style",
530
+ "chinese": "动漫上色风格",
531
+ "japanese": "アニメの着色"
532
+ },
533
+ {
534
+ "term": "blonde hair",
535
+ "type": "专用",
536
+ "subtype": "髪 Hair",
537
+ "chinese": "金发",
538
+ "japanese": "ブロンドの髪"
539
+ },
540
+ {
541
+ "term": "yellow eyes",
542
+ "type": "专用",
543
+ "subtype": "目 Eyes",
544
+ "chinese": "黄瞳",
545
+ "japanese": "黄色い目"
546
+ },
547
+ {
548
+ "term": "multicolored hair",
549
+ "type": "专用",
550
+ "subtype": "髪 Hair",
551
+ "chinese": "多色头发",
552
+ "japanese": "多色の髪"
553
+ },
554
+ {
555
+ "term": "two-tone hair",
556
+ "type": "专用",
557
+ "subtype": "髪 Hair",
558
+ "chinese": "双色渐变发",
559
+ "japanese": "ツートンの髪"
560
+ },
561
+ {
562
+ "term": "jewelry",
563
+ "type": "专用",
564
+ "subtype": "アクセサリー Accessory",
565
+ "chinese": "珠宝饰品",
566
+ "japanese": "ジュエリー"
567
+ },
568
+ {
569
+ "term": "butler costume",
570
+ "type": "专用",
571
+ "subtype": "衣類 Clothing",
572
+ "chinese": "管家服饰",
573
+ "japanese": "バトラーの衣装"
574
+ },
575
+ {
576
+ "term": "world war 1",
577
+ "type": "专用",
578
+ "subtype": "シーン Scene",
579
+ "chinese": "一战背景",
580
+ "japanese": "第一次世界大戦"
581
+ },
582
+ {
583
+ "term": "High resolution",
584
+ "type": "通用",
585
+ "subtype": "quality",
586
+ "chinese": "高清分辨率",
587
+ "japanese": "高解像度"
588
+ },
589
+ {
590
+ "term": "photorealistic",
591
+ "type": "通用",
592
+ "subtype": "スタイル Style",
593
+ "chinese": "照片级写实",
594
+ "japanese": "フォトリアリック"
595
+ },
596
+ {
597
+ "term": "4k",
598
+ "type": "通用",
599
+ "subtype": "quality",
600
+ "chinese": "4K超清",
601
+ "japanese": "4k"
602
+ },
603
+ {
604
+ "term": "Masterpiece",
605
+ "type": "通用",
606
+ "chinese": "大师级作品",
607
+ "japanese": "傑作"
608
+ },
609
+ {
610
+ "term": "extremely detailed",
611
+ "type": "通用",
612
+ "subtype": "quality",
613
+ "chinese": "极致细节",
614
+ "japanese": "非常に詳細"
615
+ },
616
+ {
617
+ "term": "professional photography",
618
+ "type": "通用",
619
+ "subtype": "スタイル Style",
620
+ "chinese": "专业摄影质感",
621
+ "japanese": "プロの写真"
622
+ },
623
+ {
624
+ "term": "sharp detail",
625
+ "type": "通用",
626
+ "subtype": "quality",
627
+ "chinese": "锐利细节",
628
+ "japanese": "シャープなディテール"
629
+ },
630
+ {
631
+ "term": "grey eyes",
632
+ "type": "专用",
633
+ "subtype": "目 Eyes",
634
+ "chinese": "灰眸",
635
+ "japanese": "灰色の目"
636
+ },
637
+ {
638
+ "term": "earrings",
639
+ "type": "专用",
640
+ "subtype": "アクセサリー Accessory",
641
+ "chinese": "耳环饰品",
642
+ "japanese": "イヤリング"
643
+ },
644
+ {
645
+ "term": "cloche hat",
646
+ "type": "专用",
647
+ "subtype": "アクセサリー Accessory",
648
+ "chinese": "钟形女帽",
649
+ "japanese": "クローシュハット"
650
+ },
651
+ {
652
+ "term": "steampunk",
653
+ "type": "专用",
654
+ "subtype": "スタイル Style",
655
+ "chinese": "蒸汽朋克主题",
656
+ "japanese": "スチームパンク"
657
+ },
658
+ {
659
+ "term": "intricate details",
660
+ "type": "通用",
661
+ "subtype": "quality",
662
+ "chinese": "复杂细节",
663
+ "japanese": "複雑な詳細"
664
+ },
665
+ {
666
+ "term": "unity 8k wallpaper",
667
+ "type": "通用",
668
+ "subtype": "スタイル Style",
669
+ "chinese": "Unity引擎8K壁纸风格",
670
+ "japanese": "Unity 8Kの壁紙"
671
+ },
672
+ {
673
+ "term": "ultra detailed",
674
+ "type": "通用",
675
+ "subtype": "quality",
676
+ "chinese": "超精细细节",
677
+ "japanese": "超詳細"
678
+ },
679
+ {
680
+ "term": "beautiful and aesthetic",
681
+ "type": "通用",
682
+ "subtype": "スタイル Style",
683
+ "chinese": "唯美艺术风格",
684
+ "japanese": "美しくて美的"
685
+ },
686
+ {
687
+ "term": "perfect lighting",
688
+ "type": "通用",
689
+ "subtype": "photography",
690
+ "chinese": "完美布光",
691
+ "japanese": "完璧な照明"
692
+ },
693
+ {
694
+ "term": "gradient coloured hair",
695
+ "type": "专用",
696
+ "subtype": "髪 Hair",
697
+ "chinese": "渐变色发型",
698
+ "japanese": "勾配色の髪"
699
+ },
700
+ {
701
+ "term": "sfw",
702
+ "type": "通用",
703
+ "subtype": "safety",
704
+ "chinese": "安全内容过滤",
705
+ "japanese": "SFW"
706
+ },
707
+ {
708
+ "term": "expressionless",
709
+ "type": "专用",
710
+ "subtype": "アクション Action",
711
+ "chinese": "无表情状态",
712
+ "japanese": "無表情"
713
+ },
714
+ {
715
+ "term": "formal",
716
+ "type": "专用",
717
+ "subtype": "衣類 Clothing",
718
+ "chinese": "正式着装",
719
+ "japanese": "フォーマル"
720
+ },
721
+ {
722
+ "term": "necktie",
723
+ "type": "专用",
724
+ "subtype": "アクセサリー Accessory",
725
+ "chinese": "领带",
726
+ "japanese": "ネクタイ"
727
+ },
728
+ {
729
+ "term": "dress shirt",
730
+ "type": "专用",
731
+ "subtype": "衣類 Clothing",
732
+ "chinese": "衬衫",
733
+ "japanese": "ドレスシャツ"
734
+ },
735
+ {
736
+ "term": "ray tracing",
737
+ "type": "通用",
738
+ "subtype": "photography",
739
+ "chinese": "光线追踪技术",
740
+ "japanese": "レイトレース"
741
+ },
742
+ {
743
+ "term": "Heavenly Cathedral",
744
+ "type": "专用",
745
+ "subtype": "シーン Scene",
746
+ "chinese": "天界大教堂场景",
747
+ "japanese": "天国大聖堂"
748
+ },
749
+ {
750
+ "term": "monk",
751
+ "type": "专用",
752
+ "subtype": "衣類 Clothing",
753
+ "chinese": "僧侣服饰",
754
+ "japanese": "モンク"
755
+ },
756
+ {
757
+ "term": "diablo style",
758
+ "type": "专用",
759
+ "subtype": "スタイル Style",
760
+ "chinese": "暗黑破坏神风格",
761
+ "japanese": "ディアブロスタイル"
762
+ },
763
+ {
764
+ "term": "ultra realistic 8k",
765
+ "type": "通用",
766
+ "subtype": "quality",
767
+ "chinese": "8K超现实精度",
768
+ "japanese": "超現実的な8K"
769
+ },
770
+ {
771
+ "term": "cinematic lighting",
772
+ "type": "通用",
773
+ "subtype": "photography",
774
+ "chinese": "电影级布光",
775
+ "japanese": "映画照明"
776
+ },
777
+ {
778
+ "term": "hyperdetailed",
779
+ "type": "通用",
780
+ "subtype": "quality",
781
+ "chinese": "超解析细节",
782
+ "japanese": "ハイパーデテール"
783
+ },
784
+ {
785
+ "term": "neutral colors",
786
+ "type": "通用",
787
+ "subtype": "color",
788
+ "chinese": "中性色调",
789
+ "japanese": "ニュートラルな色"
790
+ },
791
+ {
792
+ "term": "muted colors",
793
+ "type": "通用",
794
+ "subtype": "color",
795
+ "chinese": "低饱和配色",
796
+ "japanese": "落ち着いた色"
797
+ },
798
+ {
799
+ "term": "fine texture",
800
+ "type": "通用",
801
+ "subtype": "quality",
802
+ "chinese": "精细材质纹理",
803
+ "japanese": "細かいテクスチャー"
804
+ },
805
+ {
806
+ "term": "highly detailed",
807
+ "type": "通用",
808
+ "chinese": "高度细节",
809
+ "japanese": "非常に詳細"
810
+ },
811
+ {
812
+ "term": "absurdres",
813
+ "type": "通用",
814
+ "chinese": "超高分辨率",
815
+ "japanese": "不条理"
816
+ },
817
+ {
818
+ "term": "low light",
819
+ "type": "通用",
820
+ "chinese": "低光环境",
821
+ "japanese": "低光"
822
+ },
823
+ {
824
+ "term": "partially illuminated",
825
+ "type": "通用",
826
+ "chinese": "局部照明",
827
+ "japanese": "部分的に照らされています"
828
+ },
829
+ {
830
+ "term": "bokeh",
831
+ "type": "通用",
832
+ "chinese": "散景效果",
833
+ "japanese": "ボケ"
834
+ },
835
+ {
836
+ "term": "cinematic environment",
837
+ "type": "通用",
838
+ "chinese": "电影级环境",
839
+ "japanese": "映画環境"
840
+ },
841
+ {
842
+ "term": "volumetric lighting",
843
+ "type": "通用",
844
+ "chinese": "体积光照",
845
+ "japanese": "体積照明"
846
+ },
847
+ {
848
+ "term": "hazy background",
849
+ "type": "通用",
850
+ "chinese": "朦胧背景",
851
+ "japanese": "かすんだ背景"
852
+ },
853
+ {
854
+ "term": "high detail",
855
+ "type": "通用",
856
+ "chinese": "高细节度",
857
+ "japanese": "高い詳細"
858
+ },
859
+ {
860
+ "term": "immersive atmosphere",
861
+ "type": "通用",
862
+ "chinese": "沉浸式氛围",
863
+ "japanese": "没入型の雰囲気"
864
+ },
865
+ {
866
+ "term": "intricate texture",
867
+ "type": "通用",
868
+ "chinese": "复杂纹理",
869
+ "japanese": "複雑なテクスチャー"
870
+ },
871
+ {
872
+ "term": "blue eyeshadow",
873
+ "type": "专用",
874
+ "subtype": "目 Eyes",
875
+ "chinese": "蓝色眼影",
876
+ "japanese": "青いアイシャドウ"
877
+ },
878
+ {
879
+ "term": "black coat",
880
+ "type": "专用",
881
+ "subtype": "衣類 Clothing",
882
+ "chinese": "黑色外套",
883
+ "japanese": "黒いコート"
884
+ },
885
+ {
886
+ "term": "windblown hair",
887
+ "type": "专用",
888
+ "subtype": "髪 Hair",
889
+ "chinese": "风扬发型",
890
+ "japanese": "吹き飛ばされた髪"
891
+ },
892
+ {
893
+ "term": "white hair",
894
+ "type": "专用",
895
+ "subtype": "髪 Hair",
896
+ "chinese": "白色头发",
897
+ "japanese": "白髪"
898
+ },
899
+ {
900
+ "term": "glowing hair",
901
+ "type": "专用",
902
+ "subtype": "髪 Hair",
903
+ "chinese": "发光发丝",
904
+ "japanese": "輝く髪"
905
+ },
906
+ {
907
+ "term": "iridescent hair",
908
+ "type": "专用",
909
+ "subtype": "髪 Hair",
910
+ "chinese": "虹彩发色",
911
+ "japanese": "虹色の髪"
912
+ },
913
+ {
914
+ "term": "gradient hair",
915
+ "type": "专用",
916
+ "subtype": "髪 Hair",
917
+ "chinese": "渐变发色",
918
+ "japanese": "グラデーションヘア"
919
+ },
920
+ {
921
+ "term": "glowing yellow eye",
922
+ "type": "专用",
923
+ "subtype": "目 Eyes",
924
+ "chinese": "发光黄瞳",
925
+ "japanese": "輝く黄色の目"
926
+ },
927
+ {
928
+ "term": "fiberoptic hair",
929
+ "type": "专用",
930
+ "subtype": "髪 Hair",
931
+ "chinese": "光纤头发",
932
+ "japanese": "光ファイバーの髪"
933
+ },
934
+ {
935
+ "term": "flaming hair",
936
+ "type": "专用",
937
+ "subtype": "髪 Hair",
938
+ "chinese": "火焰发型",
939
+ "japanese": "燃える髪"
940
+ },
941
+ {
942
+ "term": "perfect details",
943
+ "type": "通用",
944
+ "chinese": "完美细节",
945
+ "japanese": "完璧な詳細"
946
+ },
947
+ {
948
+ "term": "illustration",
949
+ "type": "通用",
950
+ "chinese": "插画风格",
951
+ "japanese": "図"
952
+ },
953
+ {
954
+ "term": "glasses",
955
+ "type": "专用",
956
+ "subtype": "アクセサリー Accessory",
957
+ "chinese": "眼镜",
958
+ "japanese": "眼鏡"
959
+ },
960
+ {
961
+ "term": "shirt",
962
+ "type": "专用",
963
+ "subtype": "衣類 Clothing",
964
+ "chinese": "衬衫",
965
+ "japanese": "シャツ"
966
+ },
967
+ {
968
+ "term": "hood",
969
+ "type": "专用",
970
+ "subtype": "衣類 Clothing",
971
+ "chinese": "兜帽",
972
+ "japanese": "フード"
973
+ },
974
+ {
975
+ "term": "jacket",
976
+ "type": "专用",
977
+ "subtype": "衣類 Clothing",
978
+ "chinese": "夹克",
979
+ "japanese": "ジャケット"
980
+ },
981
+ {
982
+ "term": "red shirt",
983
+ "type": "专用",
984
+ "subtype": "衣類 Clothing",
985
+ "chinese": "红色衬衫",
986
+ "japanese": "赤いシャツ"
987
+ },
988
+ {
989
+ "term": "cloud",
990
+ "type": "专用",
991
+ "subtype": "シーン Scene",
992
+ "chinese": "云朵",
993
+ "japanese": "雲"
994
+ },
995
+ {
996
+ "term": "black-framed eyewear",
997
+ "type": "专用",
998
+ "subtype": "アクセサリー Accessory",
999
+ "chinese": "黑框眼镜",
1000
+ "japanese": "ブラックフレームアイウェア"
1001
+ },
1002
+ {
1003
+ "term": "long sleeves",
1004
+ "type": "专用",
1005
+ "subtype": "衣類 Clothing",
1006
+ "chinese": "长袖",
1007
+ "japanese": "長袖"
1008
+ },
1009
+ {
1010
+ "term": "sky",
1011
+ "type": "专用",
1012
+ "subtype": "シーン Scene",
1013
+ "chinese": "天空",
1014
+ "japanese": "空"
1015
+ },
1016
+ {
1017
+ "term": "hair between eyes",
1018
+ "type": "专用",
1019
+ "subtype": "髪 Hair",
1020
+ "chinese": "遮眼发型",
1021
+ "japanese": "目の間の髪"
1022
+ },
1023
+ {
1024
+ "term": "closed mouth",
1025
+ "type": "专用",
1026
+ "subtype": "アクション Action",
1027
+ "chinese": "闭口",
1028
+ "japanese": "閉じた口"
1029
+ },
1030
+ {
1031
+ "term": "outdoors",
1032
+ "type": "专用",
1033
+ "subtype": "シーン Scene",
1034
+ "chinese": "户外",
1035
+ "japanese": "屋外"
1036
+ },
1037
+ {
1038
+ "term": "black jacket",
1039
+ "type": "专用",
1040
+ "subtype": "衣類 Clothing",
1041
+ "chinese": "黑色夹克",
1042
+ "japanese": "黒いジャケット"
1043
+ },
1044
+ {
1045
+ "term": "short hair",
1046
+ "type": "专用",
1047
+ "subtype": "髪 Hair",
1048
+ "chinese": "短发",
1049
+ "japanese": "短い髪"
1050
+ },
1051
+ {
1052
+ "term": "hood down",
1053
+ "type": "专用",
1054
+ "subtype": "衣類 Clothing",
1055
+ "chinese": "放下兜帽",
1056
+ "japanese": "フードダウン"
1057
+ },
1058
+ {
1059
+ "term": "sunset",
1060
+ "type": "专用",
1061
+ "subtype": "シーン Scene",
1062
+ "chinese": "日落",
1063
+ "japanese": "日没"
1064
+ },
1065
+ {
1066
+ "term": "hooded jacket",
1067
+ "type": "专用",
1068
+ "subtype": "衣類 Clothing",
1069
+ "chinese": "连帽夹克",
1070
+ "japanese": "フード付きジャケット"
1071
+ },
1072
+ {
1073
+ "term": "hoodie",
1074
+ "type": "专用",
1075
+ "subtype": "衣類 Clothing",
1076
+ "chinese": "连帽衫",
1077
+ "japanese": "パーカー"
1078
+ },
1079
+ {
1080
+ "term": "sleeves past wrists",
1081
+ "type": "专用",
1082
+ "subtype": "衣類 Clothing",
1083
+ "chinese": "过腕长袖",
1084
+ "japanese": "手首を通り過ぎる袖"
1085
+ },
1086
+ {
1087
+ "term": "open jacket",
1088
+ "type": "专用",
1089
+ "subtype": "衣類 Clothing",
1090
+ "chinese": "敞开夹克",
1091
+ "japanese": "オープンジャケット"
1092
+ },
1093
+ {
1094
+ "term": "dynamic angle",
1095
+ "type": "通用",
1096
+ "chinese": "动态视角",
1097
+ "japanese": "動的角度"
1098
+ },
1099
+ {
1100
+ "term": "ultra-detailed",
1101
+ "type": "通用",
1102
+ "chinese": "超精细细节",
1103
+ "japanese": "超控除"
1104
+ },
1105
+ {
1106
+ "term": "fantasy",
1107
+ "type": "专用",
1108
+ "subtype": "スタイル Style",
1109
+ "chinese": "奇幻主题",
1110
+ "japanese": "ファンタジー"
1111
+ },
1112
+ {
1113
+ "term": "beautiful and detailed eyes",
1114
+ "type": "专用",
1115
+ "subtype": "目 Eyes",
1116
+ "chinese": "精美细致眼瞳",
1117
+ "japanese": "美しくて詳細な目"
1118
+ },
1119
+ {
1120
+ "term": "long straight hair",
1121
+ "type": "专用",
1122
+ "subtype": "髪 Hair",
1123
+ "chinese": "直长发",
1124
+ "japanese": "長いまっすぐな髪"
1125
+ },
1126
+ {
1127
+ "term": "hair flower",
1128
+ "type": "专用",
1129
+ "subtype": "アクセサリー Accessory",
1130
+ "chinese": "发间花朵饰品",
1131
+ "japanese": "髪の花"
1132
+ },
1133
+ {
1134
+ "term": "japanese long kimono with flowers",
1135
+ "type": "专用",
1136
+ "subtype": "衣類 Clothing",
1137
+ "chinese": "花卉日式长振袖",
1138
+ "japanese": "花と日本の長い着物"
1139
+ },
1140
+ {
1141
+ "term": "detached sleeves",
1142
+ "type": "专用",
1143
+ "subtype": "衣類 Clothing",
1144
+ "chinese": "离脱式袖套",
1145
+ "japanese": "袖の取り外し"
1146
+ },
1147
+ {
1148
+ "term": "wide sleeves",
1149
+ "type": "专用",
1150
+ "subtype": "衣類 Clothing",
1151
+ "chinese": "广口衣袖",
1152
+ "japanese": "広い袖"
1153
+ },
1154
+ {
1155
+ "term": "stockings",
1156
+ "type": "专用",
1157
+ "subtype": "衣類 Clothing",
1158
+ "chinese": "长筒袜",
1159
+ "japanese": "ストッキング"
1160
+ },
1161
+ {
1162
+ "term": "detail fingers",
1163
+ "type": "通用",
1164
+ "chinese": "精细手指描绘",
1165
+ "japanese": "詳細な指"
1166
+ },
1167
+ {
1168
+ "term": "magic dark forest background",
1169
+ "type": "专用",
1170
+ "subtype": "シーン Scene",
1171
+ "chinese": "魔法暗黑森林背景",
1172
+ "japanese": "魔法のダークフォレストバックグラウンド"
1173
+ },
1174
+ {
1175
+ "term": "anime",
1176
+ "type": "通���",
1177
+ "chinese": "动漫风格",
1178
+ "japanese": "アニメ"
1179
+ },
1180
+ {
1181
+ "term": "2d",
1182
+ "type": "通用",
1183
+ "chinese": "二维平面",
1184
+ "japanese": "2d"
1185
+ },
1186
+ {
1187
+ "term": "ghibli style",
1188
+ "type": "通用",
1189
+ "chinese": "吉卜力画风",
1190
+ "japanese": "ジブリスタイル"
1191
+ },
1192
+ {
1193
+ "term": "white fox tail",
1194
+ "type": "专用",
1195
+ "subtype": "アクセサリー Accessory",
1196
+ "chinese": "白狐尾巴",
1197
+ "japanese": "白いキツネの尾"
1198
+ },
1199
+ {
1200
+ "term": "black pantyhose",
1201
+ "type": "专用",
1202
+ "subtype": "衣類 Clothing",
1203
+ "chinese": "黑色连裤袜",
1204
+ "japanese": "ブラックパンスト"
1205
+ },
1206
+ {
1207
+ "term": "blue eyes",
1208
+ "type": "专用",
1209
+ "subtype": "目 Eyes",
1210
+ "chinese": "蓝色眼睛",
1211
+ "japanese": "青い目"
1212
+ }
1213
+ ]
1214
+ }
client_jp/t.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ # 设置代理服务器地址和端口
4
+ proxy_host = '127.0.0.1'
5
+ proxy_port = '7890'
6
+ os.environ['http_proxy'] = f'http://{proxy_host}:{proxy_port}'
7
+ os.environ['https_proxy'] = f'http://{proxy_host}:{proxy_port}'
8
+ import json
9
+ import asyncio
10
+ from googletrans import Translator
11
+
12
+ async def main():
13
+ with open("person.json", "r", encoding="utf-8") as f:
14
+ data = json.load(f)
15
+
16
+ translator = Translator()
17
+
18
+ for term_info in data.get("prompt_terms", []):
19
+ term_text = term_info.get("term", "")
20
+ if term_text:
21
+ try:
22
+ result = await translator.translate(term_text, src="en", dest="ja")
23
+ term_info["japanese"] = result.text
24
+ except Exception as e:
25
+ print(f"翻译失败:{term_text} - {e}")
26
+ term_info["japanese"] = ""
27
+
28
+ with open("person_jp.json", "w", encoding="utf-8") as f:
29
+ json.dump(data, f, ensure_ascii=False, indent=2)
30
+
31
+ asyncio.run(main())
dpm20_infer.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ from typing import List, Union
5
+ import numpy as np
6
+ import axengine
7
+ import torch
8
+ from PIL import Image
9
+ from transformers import CLIPTokenizer, PreTrainedTokenizer
10
+ import time
11
+ import argparse
12
+ import uuid
13
+ import os
14
+ import traceback
15
+ from diffusers import DPMSolverMultistepScheduler
16
+
17
+ # 配置日志格式
18
+ DEBUG_MODE = True
19
+ LOG_TIMESTAMP = True
20
+
21
+ def debug_log(msg):
22
+ if DEBUG_MODE:
23
+ timestamp = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] " if LOG_TIMESTAMP else ""
24
+ print(f"{timestamp}[DEBUG] {msg}")
25
+
26
+ def get_args():
27
+ try:
28
+ parser = argparse.ArgumentParser(
29
+ prog="StableDiffusion",
30
+ description="Generate picture with the input prompt using DPM++ sampler"
31
+ )
32
+ parser.add_argument("--prompt", type=str, required=False,
33
+ default="masterpiece, best quality, 1girl, (colorful),(delicate eyes and face), volumatic light, ray tracing, bust shot ,extremely detailed CG unity 8k wallpaper,solo,smile,intricate skirt,((flying petal)),(Flowery meadow) sky, cloudy_sky, moonlight, moon, night, (dark theme:1.3), light, fantasy, windy, magic sparks, dark castle,white hair",
34
+ help="the input text prompt")
35
+ parser.add_argument("--text_model_dir", type=str, required=False, default="./models/",
36
+ help="Path to text encoder and tokenizer files")
37
+ parser.add_argument("--unet_model", type=str, required=False, default="./models/unet.axmodel",
38
+ help="Path to unet axmodel model")
39
+ parser.add_argument("--vae_decoder_model", type=str, required=False, default="./models/vae_decoder.axmodel",
40
+ help="Path to vae decoder axmodel model")
41
+ parser.add_argument("--time_input", type=str, required=False,
42
+ default="./models/time_input_dpmpp_20steps.npy", # 使用DPM++时间嵌入
43
+ help="Path to time input file")
44
+ parser.add_argument("--save_dir", type=str, required=False, default="./txt2img_output_axe",
45
+ help="Path to the output image file")
46
+ parser.add_argument("--num_inference_steps", type=int, default=20,
47
+ help="Number of inference steps for DPM++ sampler")
48
+ parser.add_argument("--guidance_scale", type=float, default=7.5, help="Guidance scale for CFG")
49
+ parser.add_argument("--seed", type=int, default=None, help="Random seed")
50
+ return parser.parse_args()
51
+ except Exception as e:
52
+ print(f"参数解析失败: {str(e)}")
53
+ traceback.print_exc()
54
+ exit(1)
55
+
56
+ def get_embeds(prompt, negative_prompt, tokenizer_dir, text_encoder_dir):
57
+ """获取正负提示词的嵌入(带形状验证)"""
58
+ try:
59
+ debug_log(f"开始处理提示词: {prompt[:50]}...")
60
+ start_time = time.time()
61
+
62
+ tokenizer = CLIPTokenizer.from_pretrained(tokenizer_dir)
63
+
64
+ def process_prompt(prompt_text):
65
+ inputs = tokenizer(
66
+ prompt_text,
67
+ padding="max_length",
68
+ max_length=77,
69
+ truncation=True,
70
+ return_tensors="pt"
71
+ )
72
+ debug_log(f"Tokenizer输出形状: {inputs.input_ids.shape}")
73
+
74
+ model_path = os.path.join(text_encoder_dir, "sd15_text_encoder_sim.axmodel")
75
+ if not os.path.exists(model_path):
76
+ raise FileNotFoundError(f"文本编码器模型不存在: {model_path}")
77
+
78
+ session = axengine.InferenceSession(model_path)
79
+ outputs = session.run(None, {"input_ids": inputs.input_ids.numpy().astype(np.int32)})[0]
80
+ debug_log(f"文本编码器输出形状: {outputs.shape} | dtype: {outputs.dtype}")
81
+ return outputs
82
+
83
+ neg_start = time.time()
84
+ neg_embeds = process_prompt(negative_prompt)
85
+ pos_embeds = process_prompt(prompt)
86
+ debug_log(f"文本编码完成 | 耗时: {(time.time()-start_time):.2f}s")
87
+
88
+ # 验证形状
89
+ if neg_embeds.shape != (1, 77, 768) or pos_embeds.shape != (1, 77, 768):
90
+ raise ValueError(f"嵌入形状异常: 负面{neg_embeds.shape}, 正面{pos_embeds.shape}")
91
+
92
+ return neg_embeds, pos_embeds
93
+ except Exception as e:
94
+ print(f"获取嵌入失败: {str(e)}")
95
+ traceback.print_exc()
96
+ exit(1)
97
+
98
+ def main():
99
+ try:
100
+ debug_log("程序启动")
101
+ args = get_args()
102
+ debug_log(f"参数解析完成 | 随机种子: {args.seed} | 推理步数: {args.num_inference_steps}")
103
+
104
+ # 初始化相关配置
105
+ seed = args.seed if args.seed else int(time.time())
106
+ torch.manual_seed(seed)
107
+ np.random.seed(seed)
108
+ debug_log(f"随机种子设置完成: {seed}")
109
+
110
+ # 模型路径验证
111
+ model_paths = [
112
+ args.unet_model,
113
+ args.vae_decoder_model,
114
+ os.path.join(args.text_model_dir, 'tokenizer'),
115
+ os.path.join(args.text_model_dir, 'text_encoder')
116
+ ]
117
+ for path in model_paths:
118
+ if not os.path.exists(path):
119
+ raise FileNotFoundError(f"模型路径不存在: {path}")
120
+
121
+ # 初始化调度器
122
+ debug_log("初始化调度器...")
123
+ scheduler_start = time.time()
124
+ scheduler = DPMSolverMultistepScheduler(
125
+ num_train_timesteps=1000,
126
+ beta_start=0.00085,
127
+ beta_end=0.012,
128
+ beta_schedule="scaled_linear",
129
+ algorithm_type="dpmsolver++",
130
+ use_karras_sigmas=True
131
+ )
132
+ scheduler.set_timesteps(args.num_inference_steps)
133
+ debug_log(f"调度器初始化完成 | 耗时: {(time.time()-scheduler_start):.2f}s")
134
+
135
+ # 加载模型
136
+ debug_log("加载NPU模型...")
137
+ model_load_start = time.time()
138
+ unet_session_main = axengine.InferenceSession(args.unet_model)
139
+ vae_decoder = axengine.InferenceSession(args.vae_decoder_model)
140
+ debug_log(f"模型加载完成 | 总耗时: {(time.time()-model_load_start):.2f}s")
141
+ debug_log(f"UNET输入信息: {[str(inp) for inp in unet_session_main.get_inputs()]}")
142
+ debug_log(f"VAE输入信息: {[str(inp) for inp in vae_decoder.get_inputs()]}")
143
+
144
+ # 处理提示词
145
+ embed_start = time.time()
146
+ neg_embeds, pos_embeds = get_embeds(
147
+ args.prompt,
148
+ "sketch, duplicate, ugly...", # 简化的负面提示
149
+ os.path.join(args.text_model_dir, 'tokenizer'),
150
+ os.path.join(args.text_model_dir, 'text_encoder')
151
+ )
152
+ debug_log(f"提示词处理完成 | 总耗时: {(time.time()-embed_start):.2f}s")
153
+
154
+ # 初始化潜在变量
155
+ latent_start = time.time()
156
+ latents_shape = [1, 4, 60, 40]
157
+ generator = torch.Generator().manual_seed(seed)
158
+ latent = torch.randn(latents_shape, generator=generator)
159
+ init_scale = scheduler.init_noise_sigma
160
+ latent = latent * init_scale
161
+ debug_log(f"潜在变量初始化 | 形状: {latent.shape} | 缩放系数: {init_scale}")
162
+ latent = latent.numpy().astype(np.float32) # 确保数据类型正确
163
+ debug_log(f"潜在变量转换完成 | dtype: {latent.dtype}")
164
+
165
+ # 加载时间嵌入
166
+ debug_log(f"加载时间嵌入: {args.time_input}")
167
+ time_data = np.load(args.time_input)
168
+ if len(time_data) < args.num_inference_steps:
169
+ raise ValueError(f"时间嵌入不足: 需要{args.num_inference_steps}, 实际{len(time_data)}")
170
+ time_data = time_data[:args.num_inference_steps]
171
+ debug_log(f"时间嵌入验证通过 | 形状: {time_data.shape}")
172
+
173
+ # 采样主循环
174
+ debug_log("开始采样循环...")
175
+ total_unet_time = 0
176
+ for step_idx, timestep in enumerate(scheduler.timesteps.numpy().astype(np.int64)):
177
+ step_start = time.time()
178
+ debug_log(f"\n--- 步骤 {step_idx+1}/{args.num_inference_steps} [ts={timestep}] ---")
179
+
180
+ try:
181
+ # 验证潜在变量
182
+ if np.isnan(latent).any():
183
+ raise ValueError("潜在变量包含NaN值!")
184
+
185
+ # 准备时间嵌入
186
+ time_emb = np.expand_dims(time_data[step_idx], axis=0)
187
+ debug_log(f"时间嵌入形状: {time_emb.shape}")
188
+
189
+ # UNET推理
190
+ debug_log("运行UNET(负面提示)...")
191
+ unet_neg_start = time.time()
192
+ noise_pred_neg = unet_session_main.run(None, {
193
+ "sample": latent,
194
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
195
+ "encoder_hidden_states": neg_embeds
196
+ })[0]
197
+ debug_log(f"UNET(负面)完成 | 形状: {noise_pred_neg.shape} | 耗时: {(time.time()-unet_neg_start):.2f}s")
198
+
199
+ debug_log("运行UNET(正面提示)...")
200
+ unet_pos_start = time.time()
201
+ noise_pred_pos = unet_session_main.run(None, {
202
+ "sample": latent,
203
+ "/down_blocks.0/resnets.0/act_1/Mul_output_0": time_emb,
204
+ "encoder_hidden_states": pos_embeds
205
+ })[0]
206
+ debug_log(f"UNET(正面)完成 | 耗时: {(time.time()-unet_pos_start):.2f}s")
207
+
208
+ # CFG融合
209
+ debug_log(f"应用CFG指导(scale={args.guidance_scale})...")
210
+ noise_pred = noise_pred_neg + args.guidance_scale * (noise_pred_pos - noise_pred_neg)
211
+ debug_log(f"噪声预测范围: [{noise_pred.min():.3f}, {noise_pred.max():.3f}]")
212
+
213
+ # 转换为Tensor
214
+ latent_tensor = torch.from_numpy(latent)
215
+ noise_pred_tensor = torch.from_numpy(noise_pred)
216
+
217
+ # 调度器更新
218
+ debug_log("更新潜在变量...")
219
+ scheduler_start = time.time()
220
+ latent_tensor = scheduler.step(
221
+ model_output=noise_pred_tensor,
222
+ timestep=timestep,
223
+ sample=latent_tensor
224
+ ).prev_sample
225
+ debug_log(f"调度器更新完成 | 耗时: {(time.time()-scheduler_start):.2f}s")
226
+
227
+ # 转换回numpy
228
+ latent = latent_tensor.numpy().astype(np.float32)
229
+ debug_log(f"更新后潜在变量范围: [{latent.min():.3f}, {latent.max():.3f}]")
230
+
231
+ step_time = time.time() - step_start
232
+ total_unet_time += step_time
233
+ debug_log(f"步骤完成 | 单步耗时: {step_time:.2f}s | 累计耗时: {total_unet_time:.2f}s")
234
+
235
+ except Exception as e:
236
+ print(f"步骤 {step_idx+1} 执行失败: {str(e)}")
237
+ traceback.print_exc()
238
+ exit(1)
239
+
240
+ # VAE解码
241
+ debug_log("\n开始VAE解码...")
242
+ vae_start = time.time()
243
+ try:
244
+ latent = latent / 0.18215
245
+ debug_log(f"VAE输入范围: [{latent.min():.3f}, {latent.max():.3f}]")
246
+ image = vae_decoder.run(None, {"latent": latent})[0]
247
+ debug_log(f"VAE输出形状: {image.shape} | 耗时: {(time.time()-vae_start):.2f}s")
248
+ except Exception as e:
249
+ print(f"VAE解码失败: {str(e)}")
250
+ traceback.print_exc()
251
+ exit(1)
252
+
253
+ # 保存结果
254
+ debug_log("保存结果...")
255
+ try:
256
+ image = np.transpose(image, (0, 2, 3, 1)).squeeze(axis=0)
257
+ image_denorm = np.clip(image / 2 + 0.5, 0, 1)
258
+ image = (image_denorm * 255).round().astype("uint8")
259
+ debug_log(f"图像形状: {image.shape} | dtype: {image.dtype}")
260
+
261
+ pil_image = Image.fromarray(image[:, :, :3])
262
+ save_path = os.path.join(args.save_dir, f"{uuid.uuid4()}.png")
263
+ pil_image.save(save_path)
264
+ debug_log(f"图像保存成功: {save_path}")
265
+ except Exception as e:
266
+ print(f"保存失败: {str(e)}")
267
+ traceback.print_exc()
268
+ exit(1)
269
+
270
+ except Exception as e:
271
+ print(f"主流程执行失败: {str(e)}")
272
+ traceback.print_exc()
273
+ exit(1)
274
+
275
+ if __name__ == '__main__':
276
+ main()
gen_img.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from PIL import Image
3
+ import io
4
+
5
+ def generate_image(api_url, positive_prompt, negative_prompt=""):
6
+ payload = {
7
+ "positive_prompt": positive_prompt,
8
+ "negative_prompt": negative_prompt,
9
+ }
10
+
11
+ try:
12
+ response = requests.post(
13
+ f"{api_url}/generate",
14
+ json=payload,
15
+ timeout=30
16
+ )
17
+
18
+ if response.status_code == 200:
19
+ return Image.open(io.BytesIO(response.content))
20
+ else:
21
+ error_info = response.json().get("detail", "Unknown error")
22
+ print(f"生成失败 ({response.status_code}): {error_info}")
23
+
24
+ except Exception as e:
25
+ print(f"API调用异常: {str(e)}")
26
+
27
+ # 使用示例
28
+ api_endpoint = "http://192.168.20.104:7888"
29
+ image = generate_image(
30
+ api_endpoint,
31
+ positive_prompt="masterpiece, best quality, 1girl, (colorful),(delicate eyes and face), volumatic light, ray tracing, bust shot ,extremely detailed CG unity 8k wallpaper,solo,smile,intricate skirt,((flying petal)),(Flowery meadow) sky, cloudy_sky, moonlight, moon, night, (dark theme:1.3), light, fantasy, windy, magic sparks, dark castle,white hair",
32
+ negative_prompt="blurry, low quality, text"
33
+ )
34
+
35
+ if image:
36
+ image.save("generated_image.png")
37
+ print("图像保存成功!")
models/text_encoder/sd15_text_encoder_sim.axmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fa731c99588086044fef8e6b34445b63402a0d996b9080f0ab1a5e8dd0284ef6
3
+ size 175218267
models/time_input_dpmpp_20steps.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1ab8606928135667dd78a0fdd3fd1f689e159ac9c36d2824ea986661060a74b3
3
+ size 102528
models/tokenizer/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
models/tokenizer/special_tokens_map.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<|startoftext|>",
4
+ "lstrip": false,
5
+ "normalized": true,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "eos_token": {
10
+ "content": "<|endoftext|>",
11
+ "lstrip": false,
12
+ "normalized": true,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": "<|endoftext|>",
17
+ "unk_token": {
18
+ "content": "<|endoftext|>",
19
+ "lstrip": false,
20
+ "normalized": true,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ }
24
+ }
models/tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "bos_token": {
4
+ "__type": "AddedToken",
5
+ "content": "<|startoftext|>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false
10
+ },
11
+ "clean_up_tokenization_spaces": true,
12
+ "do_lower_case": true,
13
+ "eos_token": {
14
+ "__type": "AddedToken",
15
+ "content": "<|endoftext|>",
16
+ "lstrip": false,
17
+ "normalized": true,
18
+ "rstrip": false,
19
+ "single_word": false
20
+ },
21
+ "errors": "replace",
22
+ "model_max_length": 77,
23
+ "pad_token": "<|endoftext|>",
24
+ "tokenizer_class": "CLIPTokenizer",
25
+ "unk_token": {
26
+ "__type": "AddedToken",
27
+ "content": "<|endoftext|>",
28
+ "lstrip": false,
29
+ "normalized": true,
30
+ "rstrip": false,
31
+ "single_word": false
32
+ }
33
+ }
models/tokenizer/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
models/unet.axmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d7fcd765daca3cdc38ac24e3b28a347447c1d8356546f3546bf0a2ac3b35b5af
3
+ size 921440577
models/vae_decoder.axmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9afc2292458bf4a0bd8ba2987e742e0e7216366bc761166cfcd303a9a3bdf9cd
3
+ size 69223080
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ pillow
2
+ diffusers==0.33.1
3
+ fastapi
4
+ transformers==4.53.0
5
+ torch
6
+ uvicorn
7
+ flask
8
+ numpy==1.26.4
9
+ huggingface-hub==0.35.0
sd-launch.desktop ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [Desktop Entry]
2
+ Type=Application
3
+ Name=SD Launch
4
+ Exec=/opt/sd-launch.sh
5
+ Hidden=false
6
+ NoDisplay=false
7
+ X-GNOME-Autostart-enabled=true
8
+ StartupNotify=false
9
+ Terminal=false
sd-launch.sh ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # /opt/sd-launch.sh
3
+
4
+ # 复制你手动运行时的完整环境变量
5
+ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
6
+ export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/opt/lib:/soc/lib:$LD_LIBRARY_PATH
7
+ export PYTHONPATH=$PYTHONPATH
8
+ export DISPLAY=:0
9
+
10
+ # 等待系统完全启动
11
+ sleep 15
12
+
13
+ # 日志目录
14
+ LOG_DIR="/var/log/sd-launch"
15
+ mkdir -p "$LOG_DIR"
16
+
17
+ echo "Starting SD services at $(date)" >> "$LOG_DIR/startup.log"
18
+
19
+ # 1. 启动后端
20
+ cd /root/Desktop/SD1.5-AX650-Dark_Sushi_Mix
21
+ echo "Starting backend..." >> "$LOG_DIR/startup.log"
22
+
23
+ # 直接用 uvicorn 而不是 nohup,让脚本保持运行
24
+ uvicorn api_10steps:app --host 0.0.0.0 --port 7888 > "$LOG_DIR/backend.log" 2>&1 &
25
+ BACKEND_PID=$!
26
+ echo $BACKEND_PID > "$LOG_DIR/backend.pid"
27
+
28
+ # 等待后端启动
29
+ sleep 10
30
+ if ! kill -0 $BACKEND_PID 2>/dev/null; then
31
+ echo "Backend failed to start" >> "$LOG_DIR/startup.log"
32
+ exit 1
33
+ fi
34
+
35
+ # 2. 启动前端
36
+ cd /root/Desktop/SD1.5-AX650-Dark_Sushi_Mix/client
37
+ echo "Starting frontend..." >> "$LOG_DIR/startup.log"
38
+
39
+ python3 app.py > "$LOG_DIR/frontend.log" 2>&1 &
40
+ FRONTEND_PID=$!
41
+ echo $FRONTEND_PID > "$LOG_DIR/frontend.pid"
42
+
43
+ # 3. 等待前端端口就绪
44
+ echo "Waiting for frontend..." >> "$LOG_DIR/startup.log"
45
+ for i in {1..30}; do
46
+ if curl -s http://localhost:5000/ >/dev/null 2>&1; then
47
+ break
48
+ fi
49
+ sleep 2
50
+ done
51
+
52
+ # 4. 打开浏览器并全屏
53
+ echo "Opening browser..." >> "$LOG_DIR/startup.log"
54
+
55
+ # 等待图形界面完全就绪
56
+ sleep 5
57
+
58
+ # 确保 DISPLAY 正确设置
59
+ export DISPLAY=:0
60
+ echo "DISPLAY=$DISPLAY" >> "$LOG_DIR/startup.log"
61
+ echo "Current user: $(whoami)" >> "$LOG_DIR/startup.log"
62
+
63
+ # 直接使用 Firefox kiosk 模式
64
+ if command -v firefox >/dev/null 2>&1; then
65
+ echo "Starting Firefox in kiosk mode..." >> "$LOG_DIR/startup.log"
66
+ firefox --kiosk http://localhost:5000/ >> "$LOG_DIR/browser.log" 2>&1 &
67
+ BROWSER_PID=$!
68
+ echo "Firefox started with PID: $BROWSER_PID" >> "$LOG_DIR/startup.log"
69
+
70
+ # 验证浏览器进程是否启动成功
71
+ sleep 3
72
+ if kill -0 $BROWSER_PID 2>/dev/null; then
73
+ echo "Firefox process confirmed running" >> "$LOG_DIR/startup.log"
74
+ else
75
+ echo "Firefox process failed to start" >> "$LOG_DIR/startup.log"
76
+ cat "$LOG_DIR/browser.log" >> "$LOG_DIR/startup.log"
77
+ fi
78
+ else
79
+ echo "Firefox not found" >> "$LOG_DIR/startup.log"
80
+ fi