Wanlau commited on
Commit
18720f0
·
1 Parent(s): e669091

parameter migration and overlay for multiple expressions by native parameter groups

Browse files
Files changed (4) hide show
  1. .gitignore +2 -1
  2. MiracleCacheTools.py +138 -0
  3. app.py +570 -2
  4. requirements.txt +3 -1
.gitignore CHANGED
@@ -1,2 +1,3 @@
1
  **/__pycache__/
2
- **/test.py
 
 
1
  **/__pycache__/
2
+ **/test.py
3
+ test/
MiracleCacheTools.py CHANGED
@@ -1,5 +1,8 @@
1
  import re
2
  import colorsys
 
 
 
3
 
4
 
5
  def colorStringProcessRGB(color_str):
@@ -51,8 +54,143 @@ def colorStringProcessRGB(color_str):
51
 
52
  raise ValueError("Invalid color string format")
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  ######
55
  #color_str = "rgb(190.71875, 42.242530153508774, 42.242530153508774)"
56
  #color_str = "rgba(190.71875, 42.242530153508774, 42.242530153508774, 1)"
57
  #r, g, b = colorStringProcessRGB(color_str)
58
  #print(r, g, b)
 
 
 
 
 
 
 
 
1
  import re
2
  import colorsys
3
+ import json
4
+
5
+ import pandas as pd
6
 
7
 
8
  def colorStringProcessRGB(color_str):
 
54
 
55
  raise ValueError("Invalid color string format")
56
 
57
+ def cdiParametersListFileGet(input_path, output_path):
58
+ with open(input_path, "r", encoding="utf8") as file:
59
+ data_raw = json.load(file)
60
+
61
+ data_result = cdiParametersListGet(data_raw)
62
+ with open(output_path, "w", encoding="utf8") as file:
63
+ json.dump(data_result, file, ensure_ascii=False)
64
+
65
+ return 0
66
+
67
+
68
+ def cdiParametersListGet(data_raw):
69
+ data_result = {}
70
+ for param in data_raw["Parameters"]:
71
+ pid = param["Id"]
72
+ pnom = param["Name"]
73
+ if pid in data_result:
74
+ raise ValueError(f"Duplicate parameter ID found: {pid}")
75
+ else:
76
+ data_result[pid] = {"Name": pnom}
77
+
78
+ return data_result
79
+
80
+ def cdiParametersGroupsDataFileGet(input_path, output_path):
81
+ with open(input_path, "r", encoding="utf8") as file:
82
+ data_raw = json.load(file)
83
+
84
+ data_result = cdiParametersGroupsDataGet(data_raw)
85
+ with open(output_path, "w", encoding="utf8") as file:
86
+ json.dump(data_result, file, ensure_ascii=False)
87
+
88
+ return 0
89
+
90
+ ## 目前仅处理单层分组
91
+ def cdiParametersGroupsDataGet(data_raw):
92
+ data_result = {}
93
+ for group in data_raw["ParameterGroups"]:
94
+ gid = group["Id"]
95
+ gnom = group["Name"]
96
+ data_result[gid] = {"Name":gnom, "Parameters":{}}
97
+
98
+ for param in data_raw["Parameters"]:
99
+ pid = param["Id"]
100
+ pnom = param["Name"]
101
+ pgid = param["GroupId"]
102
+ if pgid in data_result:
103
+ data_result[pgid]["Parameters"][pid] = {"Name": pnom}
104
+ else:
105
+ raise ValueError(f"unknown group ID : {pgid}")
106
+
107
+ return data_result
108
+
109
+ def parametersListTextGet(parameters_list_dict):
110
+ df = pd.DataFrame(([id, parameters_list_dict[id]["Name"]] for id in parameters_list_dict), columns=["id", "name"])
111
+ df["text"] = df.apply(lambda row : row["id"] + " : " + row["name"], axis=1)
112
+ return df
113
+
114
+ def parameterPresetDataFramePreviewGet(parameter_preset_dict):
115
+ result_list = []
116
+ text_list = []
117
+ for ppid, ppdata in parameter_preset_dict.items():
118
+ text_list.clear()
119
+ for pid in ppdata:
120
+ pname = ppdata[pid]["Name"]
121
+ text_list.append(f"{pid} : {pname}")
122
+ result_list.append([ppid, text_list.copy()])
123
+
124
+ df = pd.DataFrame(result_list, columns=["预设名称", "参数列表"])
125
+
126
+ return df
127
+
128
+ def expressionParametersMigration(parameters_list: list|dict, data_acceptor, data_donor):
129
+ data_result = data_acceptor.copy()
130
+ pdata_acceptor = dict((prm["Id"],prm) for prm in data_acceptor["Parameters"])
131
+ pdata_donor = dict((prm["Id"],prm) for prm in data_donor["Parameters"])
132
+ pdata_result = pdata_acceptor.copy()
133
+ for parameter in parameters_list:
134
+ if parameter in pdata_donor:
135
+ pdata_result[parameter] = pdata_donor[parameter]
136
+ else:
137
+ if parameter in pdata_result:
138
+ del pdata_result[parameter]
139
+
140
+ parameters_list_result = list((pdata for pid, pdata in pdata_result.items()))
141
+ data_result["Parameters"] = parameters_list_result
142
+
143
+ return data_result
144
+
145
+ def expressionParametersMigrationByGroups(parameters_groups: dict, data_acceptor, data_donor):
146
+ parameters_list = []
147
+ for gid, gdata in parameters_groups.items():
148
+ for param in gdata["Parameters"]:
149
+ if param not in parameters_list:
150
+ parameters_list.append(param)
151
+
152
+ data_result = expressionParametersMigration(parameters_list, data_acceptor, data_donor)
153
+
154
+ return data_result
155
+
156
+ ## 引用:
157
+ ## gr.Markdown("新表情的参数会覆盖原有的同名参数,目前有『迁移』『叠加』两种操作。<br>『迁移』和之前一样会删掉参考列表中原表情有而新表情没有的参数,『叠加』则不会。<br>当参数列表包含所有相关参数时,其『迁移』结果新表情将会完全覆盖原表情,『叠加』结果则类似于VTS的表情叠加。")
158
+ ## 起名可能不大准确,总之就是这么回事。
159
+ def expressionParametersOverlay(parameters_list: list|dict, data_acceptor, data_donor):
160
+ data_result = data_acceptor.copy()
161
+ pdata_acceptor = dict((prm["Id"],prm) for prm in data_acceptor["Parameters"])
162
+ pdata_donor = dict((prm["Id"],prm) for prm in data_donor["Parameters"])
163
+ pdata_result = pdata_acceptor.copy()
164
+ for parameter in parameters_list:
165
+ ## 就是没有else部分
166
+ if parameter in pdata_donor:
167
+ pdata_result[parameter] = pdata_donor[parameter]
168
+
169
+ parameters_list_result = list((pdata for pid, pdata in pdata_result.items()))
170
+ data_result["Parameters"] = parameters_list_result
171
+
172
+ return data_result
173
+
174
+ def expressionParametersOverlayByGroups(parameters_groups: dict, data_acceptor, data_donor):
175
+ parameters_list = []
176
+ for gid, gdata in parameters_groups.items():
177
+ for param in gdata["Parameters"]:
178
+ if param not in parameters_list:
179
+ parameters_list.append(param)
180
+
181
+ data_result = expressionParametersOverlay(parameters_list, data_acceptor, data_donor)
182
+
183
+ return data_result
184
+
185
  ######
186
  #color_str = "rgb(190.71875, 42.242530153508774, 42.242530153508774)"
187
  #color_str = "rgba(190.71875, 42.242530153508774, 42.242530153508774, 1)"
188
  #r, g, b = colorStringProcessRGB(color_str)
189
  #print(r, g, b)
190
+
191
+ #cdiParametersListFileGet("data/general_model_Juumon/general_model_Juumon.cdi3.json", "data/cdiParametersList.json")
192
+ #cdiParametersGroupsDataFileGet("data/general_model_Juumon/general_model_Juumon.cdi3.json", "data/cdiParametersGroupsData.json")
193
+ #with open("data/test.exp3.json", "r", encoding="utf8") as file:
194
+ # data = json.load(file)
195
+ #expressionParametersMigration(["Param2", "HC82"], data, {"Parameters":[]})
196
+
app.py CHANGED
@@ -1,9 +1,24 @@
1
  import colorsys
 
 
 
2
 
3
  import gradio as gr
 
4
 
5
  import MiracleCacheTools
6
 
 
 
 
 
 
 
 
 
 
 
 
7
  def numInputCheck(num, min, max):
8
  if num < min:
9
  num = min
@@ -98,6 +113,239 @@ def colorInputProcess(color_str):
98
 
99
  return color_hex, r, g, b, hls_h, hls_l, hls_s, hsv_h, hsv_s, hsv_v
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  with gr.Blocks(title="MiracleCacheTools") as demo:
102
 
103
  gr.Markdown("## 奇迹缓缓辅助工具箱")
@@ -194,9 +442,329 @@ with gr.Blocks(title="MiracleCacheTools") as demo:
194
  )
195
 
196
 
197
- with gr.Tab("参数批量迁移(测试版)"):
198
- gr.Markdown("缓不过来了,摆了。")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
 
200
 
201
 
202
  demo.launch()
 
1
  import colorsys
2
+ import os
3
+ import json
4
+ from tempfile import NamedTemporaryFile
5
 
6
  import gradio as gr
7
+ import pandas as pd
8
 
9
  import MiracleCacheTools
10
 
11
+ parameters_list_path = "data/cdiParametersList.json"
12
+ parameters_groups_data_path = "data/cdiParametersGroupsData.json"
13
+
14
+ EXP_DATA_TEMP_LIST_LENGTH = 16
15
+
16
+ parameter_preset_files = []
17
+ for root, dirs, files in os.walk("data/parameter_presets"):
18
+ for file in files:
19
+ if file.endswith(".json"):
20
+ parameter_preset_files.append(os.path.join(root, file))
21
+
22
  def numInputCheck(num, min, max):
23
  if num < min:
24
  num = min
 
113
 
114
  return color_hex, r, g, b, hls_h, hls_l, hls_s, hsv_h, hsv_s, hsv_v
115
 
116
+ def parameterPresetFileSelectUpdate(parameter_preset_file_select_type):
117
+ if parameter_preset_file_select_type == "选择已有文件":
118
+ return gr.Dropdown(value=None, interactive=True), gr.File(value=None, interactive=False)
119
+ elif parameter_preset_file_select_type == "上传本地文件":
120
+ return gr.Dropdown(value=None, interactive=False), gr.File(value=None, interactive=True)
121
+ else:
122
+ return gr.Dropdown(value=None, interactive=False), gr.File(value=None, interactive=False)
123
+
124
+ def parameterPresetFileProcess(parameter_preset_file):
125
+ with open(parameter_preset_file, "r", encoding="utf8") as file:
126
+ data = json.load(file)
127
+
128
+ parameter_preset_list = list(data)
129
+
130
+ return gr.Dropdown(choices=parameter_preset_list), data
131
+
132
+ def processButton0201Click(parameter_preset, expression_acceptor_file, expression_donor_file, parameter_preset_data):
133
+ if parameter_preset is None:
134
+ raise ValueError("parameter preset not found")
135
+ if expression_acceptor_file is None:
136
+ raise ValueError("expression acceptor not found")
137
+ if expression_donor_file is None:
138
+ raise ValueError("expression donor not found")
139
+
140
+ with open(expression_acceptor_file, "r", encoding="utf8") as file:
141
+ data_acceptor = json.load(file)
142
+
143
+ with open(expression_donor_file, "r", encoding="utf8") as file:
144
+ data_donor = json.load(file)
145
+
146
+ parameters_list = list(parameter_preset_data[parameter_preset])
147
+
148
+ data_result = MiracleCacheTools.expressionParametersMigration(parameters_list, data_acceptor, data_donor)
149
+
150
+ with NamedTemporaryFile(suffix=".exp3.json", delete=False, mode="w", encoding="utf8") as file:
151
+ json.dump(data_result, file, ensure_ascii=False, indent=4)
152
+ result_file_path = file.name
153
+
154
+ return result_file_path
155
+
156
+ def useButton0202Click(select_type, file_select, file_upload):
157
+ if select_type == "选择已有文件":
158
+ if file_select is None:
159
+ raise ValueError("parameter preset file not found")
160
+ file = file_select
161
+
162
+ elif select_type == "上传本地文件":
163
+ if file_upload is None:
164
+ raise ValueError("parameter preset file not found")
165
+ file = file_upload
166
+
167
+ else:
168
+ raise ValueError(f"unknown select type : {select_type}")
169
+
170
+ with open(file, "r", encoding="utf8") as f:
171
+ data = json.load(f)
172
+
173
+ return data
174
+
175
+ def useButton0202aClick(file_upload):
176
+ if file_upload is None:
177
+ raise ValueError("parameters list update file not found")
178
+
179
+ with open(file_upload, "r", encoding="utf8") as file:
180
+ data_raw = json.load(file)
181
+
182
+ data_result = MiracleCacheTools.cdiParametersListGet(data_raw)
183
+ data_result_df = MiracleCacheTools.parametersListTextGet(data_result)
184
+
185
+ return data_result, data_result_df
186
+
187
+ def addButton0202Click(data_raw, name, params, parameters_list_df):
188
+ if name is None:
189
+ raise ValueError("parameter preset name is empty")
190
+ if params is None:
191
+ params = []
192
+
193
+ name = name.strip()
194
+ if name == "":
195
+ raise ValueError("parameter preset name is empty")
196
+ if name in data_raw:
197
+ raise ValueError(f"Duplicate parameter preset name found: {name}")
198
+
199
+ pdata = {}
200
+ for param in params:
201
+ pid = parameters_list_df[parameters_list_df["text"]==param].reset_index(drop=True)["id"][0]
202
+ pname = parameters_list_df[parameters_list_df["text"]==param].reset_index(drop=True)["name"][0]
203
+ pdata[pid] = {"Name": pname}
204
+
205
+ data_raw[name] = pdata.copy()
206
+
207
+ return data_raw, "", []
208
+
209
+ def deleteButton0202Click(data_raw, delete_list):
210
+ if delete_list is None:
211
+ delete_list = []
212
+
213
+ for name in delete_list:
214
+ if name in data_raw:
215
+ del data_raw[name]
216
+
217
+ return data_raw, []
218
+
219
+ def saveButton0202Click(data_raw):
220
+ with NamedTemporaryFile(suffix=".json", delete=False, mode="w", encoding="utf8") as file:
221
+ json.dump(data_raw, file, ensure_ascii=False)
222
+ result_file_path = file.name
223
+
224
+ return result_file_path
225
+
226
+ def updateParametersGroupsDataByCdiFile(file_upload):
227
+ if file_upload is None:
228
+ raise ValueError("parameters groups data update file not found")
229
+
230
+ with open(file_upload, "r", encoding="utf8") as file:
231
+ data_raw = json.load(file)
232
+
233
+ data_result = MiracleCacheTools.cdiParametersGroupsDataGet(data_raw)
234
+ data_result_df = MiracleCacheTools.parametersListTextGet(data_result)
235
+
236
+ return data_result, data_result_df
237
+
238
+ def processButton0203bClick(parameters_groups, expression_acceptor_file, expression_donor_file, parameters_groups_data, parameters_groups_dataframe):
239
+ if parameters_groups is None:
240
+ parameters_groups = []
241
+ if expression_acceptor_file is None:
242
+ raise ValueError("expression acceptor not found")
243
+ if expression_donor_file is None:
244
+ raise ValueError("expression donor not found")
245
+
246
+ with open(expression_acceptor_file, "r", encoding="utf8") as file:
247
+ data_acceptor = json.load(file)
248
+
249
+ with open(expression_donor_file, "r", encoding="utf8") as file:
250
+ data_donor = json.load(file)
251
+
252
+ groups = {}
253
+ for gtext in parameters_groups:
254
+ gid = parameters_groups_dataframe[parameters_groups_dataframe["text"]==gtext].reset_index(drop=True)["id"][0]
255
+ groups[gid] = parameters_groups_data[gid]
256
+
257
+ data_result = MiracleCacheTools.expressionParametersMigrationByGroups(groups, data_acceptor, data_donor)
258
+
259
+ with NamedTemporaryFile(suffix=".exp3.json", delete=False, mode="w", encoding="utf8") as file:
260
+ json.dump(data_result, file, ensure_ascii=False, indent=4)
261
+ result_file_path = file.name
262
+
263
+ return result_file_path
264
+
265
+ def multipleExpressionsParametersMigration(expression_donor_files, parameters_groups, expression_data_temp_list, parameters_groups_data, parameters_groups_dataframe):
266
+ if parameters_groups is None:
267
+ return expression_data_temp_list
268
+ elif len(parameters_groups) == 0:
269
+ return expression_data_temp_list
270
+
271
+ if expression_donor_files is None:
272
+ return expression_data_temp_list
273
+ elif len(expression_donor_files) == 0:
274
+ return expression_data_temp_list
275
+
276
+ data_result = expression_data_temp_list[-1]
277
+ data_list_result = expression_data_temp_list.copy()
278
+ groups = {}
279
+ for gtext in parameters_groups:
280
+ gid = parameters_groups_dataframe[parameters_groups_dataframe["text"]==gtext].reset_index(drop=True)["id"][0]
281
+ groups[gid] = parameters_groups_data[gid]
282
+
283
+ for expression_donor_file in expression_donor_files:
284
+ with open(expression_donor_file, "r", encoding="utf8") as file:
285
+ data_donor = json.load(file)
286
+ data_result = MiracleCacheTools.expressionParametersMigrationByGroups(groups, data_result, data_donor)
287
+
288
+ data_list_result.append(data_result.copy())
289
+ if len(data_list_result) > EXP_DATA_TEMP_LIST_LENGTH:
290
+ data_list_result = data_list_result[-EXP_DATA_TEMP_LIST_LENGTH:]
291
+
292
+ return data_list_result
293
+
294
+ def multipleExpressionsParametersOverlay(expression_donor_files, parameters_groups, expression_data_temp_list, parameters_groups_data, parameters_groups_dataframe):
295
+ if parameters_groups is None:
296
+ return expression_data_temp_list
297
+ elif len(parameters_groups) == 0:
298
+ return expression_data_temp_list
299
+
300
+ if expression_donor_files is None:
301
+ return expression_data_temp_list
302
+ elif len(expression_donor_files) == 0:
303
+ return expression_data_temp_list
304
+
305
+ data_result = expression_data_temp_list[-1]
306
+ data_list_result = expression_data_temp_list.copy()
307
+ groups = {}
308
+ for gtext in parameters_groups:
309
+ gid = parameters_groups_dataframe[parameters_groups_dataframe["text"]==gtext].reset_index(drop=True)["id"][0]
310
+ groups[gid] = parameters_groups_data[gid]
311
+
312
+ for expression_donor_file in expression_donor_files:
313
+ with open(expression_donor_file, "r", encoding="utf8") as file:
314
+ data_donor = json.load(file)
315
+ data_result = MiracleCacheTools.expressionParametersOverlayByGroups(groups, data_result, data_donor)
316
+
317
+ data_list_result.append(data_result.copy())
318
+ if len(data_list_result) > EXP_DATA_TEMP_LIST_LENGTH:
319
+ data_list_result = data_list_result[-EXP_DATA_TEMP_LIST_LENGTH:]
320
+
321
+ return data_list_result
322
+
323
+ def expressionDataTempListAppendEmptyExpressionsDict(expression_data_temp_list):
324
+ expression_data_temp_list.append({"Type": "Live2D Expression", "Parameters": []})
325
+ if len(expression_data_temp_list) > EXP_DATA_TEMP_LIST_LENGTH:
326
+ expression_data_temp_list = expression_data_temp_list[-EXP_DATA_TEMP_LIST_LENGTH:]
327
+
328
+ return expression_data_temp_list
329
+
330
+ def saveButton0204bClick(data_raw_list):
331
+ data_raw = data_raw_list[-1]
332
+ with NamedTemporaryFile(suffix=".exp3.json", delete=False, mode="w", encoding="utf8") as file:
333
+ json.dump(data_raw, file, ensure_ascii=False)
334
+ result_file_path = file.name
335
+
336
+ return result_file_path
337
+
338
+ def expressionDataTempListStateChange(expression_data_temp_list):
339
+ expression_data = expression_data_temp_list[-1]
340
+ if len(expression_data_temp_list) <= 1:
341
+ back_interactive = False
342
+ else:
343
+ back_interactive = True
344
+
345
+ return gr.JSON(value=expression_data), gr.Button(interactive=back_interactive)
346
+
347
+
348
+
349
  with gr.Blocks(title="MiracleCacheTools") as demo:
350
 
351
  gr.Markdown("## 奇迹缓缓辅助工具箱")
 
442
  )
443
 
444
 
445
+ with gr.Tab("表情参数批量迁移"):
446
+
447
+ with open(parameters_list_path, "r", encoding="utf8") as file:
448
+ parameters_list_dict = json.load(file)
449
+ parameters_list_dict_state = gr.State(parameters_list_dict)
450
+ parameters_list_df_state = gr.State(MiracleCacheTools.parametersListTextGet(parameters_list_dict))
451
+
452
+ ## 此处参数分组表格和参数表格使用同一个函数获取
453
+ with open(parameters_groups_data_path, "r", encoding="utf8") as file:
454
+ parameters_groups_data_dict = json.load(file)
455
+ parameters_groups_data_dict_state = gr.State(parameters_groups_data_dict)
456
+ parameters_groups_data_df_state = gr.State(MiracleCacheTools.parametersListTextGet(parameters_groups_data_dict))
457
+
458
+
459
+
460
+ gr.Markdown("表情参数批量迁移,试验性功能,请谨慎使用。<br>实际效果为,根据参考的参数列表,将参数施主的表情参数复制到参数受主中,覆盖原有表情参数或新增表情参数。(详见下方的详细说明)<br>参数列表应随奇迹缓缓一齐更新。<br>工具不会处理数据文件可能存在的格式问题,请自行确保数据文件格式正确并备份原始数据。")
461
+
462
+ with gr.Tab("使用参数预设"):
463
+
464
+ parameter_preset_data_state = gr.State({})
465
+
466
+ with gr.Row():
467
+ with gr.Column(scale=1):
468
+ gr.Markdown("#### 参数预设文件")
469
+ gr.Markdown("选择或上传参数预设文件并选择参数预设")
470
+ parameter_preset_file_select_type = gr.Radio(choices=["选择已有文件", "上传本地文件"], value="选择已有文件", label="参数预设文件选择方式", interactive=True)
471
+ parameter_preset_file_select = gr.Dropdown(choices=parameter_preset_files, value=None, multiselect=False, label="选择参数预设文件", interactive=True)
472
+ parameter_preset_file_upload = gr.File(file_types=[".json"], label="上传参数预设文件", interactive=False)
473
+ parameter_preset = gr.Dropdown(choices=[], value=None, multiselect=False, label="选择参数预设", interactive=True)
474
+
475
+ with gr.Column(scale=1):
476
+ expression_acceptor_file = gr.File(file_types=[".json"], label="上传参数受主文件", interactive=True)
477
+ expression_donor_file = gr.File(file_types=[".json"], label="上传参数施主文件", interactive=True)
478
+ with gr.Row():
479
+ process_button_0201 = gr.Button("处理", variant="primary")
480
+ clear_button_0201 = gr.Button("清空", variant="primary")
481
+ output_file_0201 = gr.File(label="输出文件", interactive=False)
482
+
483
+ gr.Markdown("#### 使用方法:")
484
+ gr.Markdown("1. 选择或上传参数预设文件,选择参数预设。<br>2. 上传参数受主文件和参数施主文件。")
485
+ gr.Markdown("#### 原理说明:")
486
+ gr.Markdown("遍历预设列表中的参数。<br>若其存在于施主文件中,则将其复制到受主文件中,覆盖原有参数或新增参数。<br>若其不存在于施主文件中,则删去受主文件中的该参数(若存在)。")
487
+
488
+ parameter_preset_file_select_type.change(
489
+ fn=parameterPresetFileSelectUpdate,
490
+ inputs=[parameter_preset_file_select_type],
491
+ outputs=[parameter_preset_file_select, parameter_preset_file_upload]
492
+ )
493
+
494
+ parameter_preset_file_select.input(
495
+ fn=parameterPresetFileProcess,
496
+ inputs=[parameter_preset_file_select],
497
+ outputs=[parameter_preset, parameter_preset_data_state]
498
+ )
499
+
500
+ parameter_preset_file_upload.upload(
501
+ fn=parameterPresetFileProcess,
502
+ inputs=[parameter_preset_file_upload],
503
+ outputs=[parameter_preset, parameter_preset_data_state]
504
+ )
505
+
506
+ process_button_0201.click(
507
+ fn=processButton0201Click,
508
+ inputs=[parameter_preset, expression_acceptor_file, expression_donor_file, parameter_preset_data_state],
509
+ outputs=[output_file_0201]
510
+ )
511
+
512
+ clear_button_0201.click(
513
+ fn=lambda : ["选择已有文件", [], None, [], None, None],
514
+ outputs=[parameter_preset_file_select_type, parameter_preset_file_select, parameter_preset_file_upload, parameter_preset, expression_acceptor_file, expression_donor_file]
515
+ )
516
+
517
+ with gr.Tab("自定义参数预设"):
518
+
519
+ parameter_preset_0202_state = gr.State({})
520
+
521
+ with gr.Row():
522
+ with gr.Column(scale=1):
523
+ gr.Markdown("#### 参数预设模板文件")
524
+ gr.Markdown("选择或上传参数预设文件并以其作为参数预设模板")
525
+ parameter_preset_file_select_type_0202 = gr.Radio(choices=["选择已有文件", "上传本地文件"], value="选择已有文件", label="参数预设文件选择方式", interactive=True)
526
+ parameter_preset_file_select_0202 = gr.Dropdown(choices=parameter_preset_files, value=None, multiselect=False, label="选择参数预设文件", interactive=True)
527
+ parameter_preset_file_upload_0202 = gr.File(file_types=[".json"], label="上传参数预设文件", interactive=False)
528
+ with gr.Row():
529
+ use_button_0202 = gr.Button("使用参数预设模板", variant="primary")
530
+ clear_button_0202 = gr.Button("清空", variant="primary")
531
+
532
+ gr.Markdown("#### 参数列表更新")
533
+ gr.Markdown("默认使用现有参数列表<br>可上传『.cdi3.json』文件以更新参数列表")
534
+ parameters_list_update_file = gr.File(file_types=[".json"], show_label=False)
535
+ with gr.Row():
536
+ use_button_0202a = gr.Button("更新参数列表", variant="primary")
537
+
538
+ with gr.Column(scale=1):
539
+ gr.Markdown("#### 添加参数预设")
540
+ gr.Markdown("注意,预设名称不可与现有的重复。")
541
+ parameter_preset_name = gr.Textbox(value="", label="参数预设名称", interactive=True)
542
+ parameter_preset_parameters = gr.Dropdown(choices=parameters_list_df_state.value["text"].to_list(), value=None, multiselect=True, label="选择预设参数", interactive=True, info="参数过多时,下拉框存在局限,后续将进行优化。")
543
+ with gr.Row():
544
+ add_button_0202 = gr.Button("添加参数预设", variant="primary")
545
+ clear_button_0202b = gr.Button("清空", variant="primary")
546
+ gr.Markdown("#### 删除参数预设")
547
+ parameter_preset_delete = gr.Dropdown(choices=list(parameter_preset_0202_state.value), value=None, multiselect=True, label="选择要删除的参数预设", interactive=True)
548
+ with gr.Row():
549
+ delete_button_0202 = gr.Button("删除参数预设", variant="primary")
550
+ clear_button_0202c = gr.Button("清空", variant="primary")
551
+
552
+ gr.Markdown("#### 参数预设预览")
553
+ parameter_preset_preview = gr.Dataframe(MiracleCacheTools.parameterPresetDataFramePreviewGet(parameter_preset_0202_state.value), headers=["预设名称", "参数列表"], interactive=False, label="参数预设预览")
554
+
555
+ gr.Markdown("#### 参数预设保存")
556
+ save_button_0202 = gr.Button("保存参数预设文件", variant="primary")
557
+ output_file_0202 = gr.File(label="输出文件", interactive=False)
558
+
559
+ parameter_preset_file_select_type_0202.change(
560
+ fn=parameterPresetFileSelectUpdate,
561
+ inputs=[parameter_preset_file_select_type_0202],
562
+ outputs=[parameter_preset_file_select_0202, parameter_preset_file_upload_0202]
563
+ )
564
+
565
+ use_button_0202.click(
566
+ fn=useButton0202Click,
567
+ inputs=[parameter_preset_file_select_type_0202, parameter_preset_file_select_0202, parameter_preset_file_upload_0202],
568
+ outputs=[parameter_preset_0202_state]
569
+ )
570
+
571
+ clear_button_0202.click(
572
+ fn=lambda :["选择已有文件", [], None],
573
+ outputs=[parameter_preset_file_select_type_0202, parameter_preset_file_select_0202, parameter_preset_file_upload_0202]
574
+ )
575
+
576
+ use_button_0202a.click(
577
+ fn=useButton0202aClick,
578
+ inputs=[parameters_list_update_file],
579
+ outputs=[parameters_list_dict_state, parameters_list_df_state]
580
+ )
581
+
582
+ add_button_0202.click(
583
+ fn=addButton0202Click,
584
+ inputs=[parameter_preset_0202_state, parameter_preset_name, parameter_preset_parameters, parameters_list_df_state],
585
+ outputs=[parameter_preset_0202_state, parameter_preset_name, parameter_preset_parameters]
586
+ )
587
+
588
+ clear_button_0202b.click(
589
+ fn=lambda : ["", []],
590
+ outputs=[parameter_preset_name, parameter_preset_parameters]
591
+ )
592
+
593
+ delete_button_0202.click(
594
+ fn=deleteButton0202Click,
595
+ inputs=[parameter_preset_0202_state, parameter_preset_delete],
596
+ outputs=[parameter_preset_0202_state, parameter_preset_delete]
597
+ )
598
+
599
+ clear_button_0202c.click(
600
+ fn=lambda : [[]],
601
+ outputs=[parameter_preset_delete]
602
+ )
603
+
604
+ save_button_0202.click(
605
+ fn=saveButton0202Click,
606
+ inputs=[parameter_preset_0202_state],
607
+ outputs=[output_file_0202]
608
+ )
609
+
610
+ parameters_list_df_state.change(
611
+ fn=lambda df:gr.Dropdown(choices=df["text"].to_list()),
612
+ inputs=[parameters_list_df_state],
613
+ outputs=[parameter_preset_parameters]
614
+ )
615
+
616
+ parameter_preset_0202_state.change(
617
+ fn=lambda preset:[gr.Dataframe(MiracleCacheTools.parameterPresetDataFramePreviewGet(preset)), gr.Dropdown(choices=list(preset))],
618
+ inputs=[parameter_preset_0202_state],
619
+ outputs=[parameter_preset_preview, parameter_preset_delete]
620
+ )
621
+
622
+ with gr.Tab("使用原生参数分组"):
623
+ gr.Markdown("使用原生的参数分组作为参考的参数列表。<br>分组可多选。")
624
+
625
+ with gr.Row():
626
+ with gr.Column(scale=1):
627
+ parameters_groups_select_0203 = gr.Dropdown(choices=parameters_groups_data_df_state.value["text"].to_list(), value=None, multiselect=True, interactive=True, label="选择参数分组")
628
+ with gr.Row():
629
+ all_button_0203 = gr.Button("全选", variant="primary")
630
+ #clear_button_0203 = gr.Button("清空", variant="primary")
631
+
632
+ gr.Markdown("#### 参数分组数据更新")
633
+ gr.Markdown("默认使用现有参数分组数据<br>可上传『.cdi3.json』文件以更新参数分组数据")
634
+ parameters_groups_data_update_file = gr.File(file_types=[".json"], show_label=False)
635
+ with gr.Row():
636
+ use_button_0203a = gr.Button("更新参数分组", variant="primary")
637
+
638
+ with gr.Column(scale=1):
639
+ expression_acceptor_file_0203 = gr.File(file_types=[".json"], label="上传参数受主文件", interactive=True)
640
+ expression_donor_file_0203 = gr.File(file_types=[".json"], label="上传参数施主文件", interactive=True)
641
+ with gr.Row():
642
+ process_button_0203b = gr.Button("处理", variant="primary")
643
+ clear_button_0203b = gr.Button("清空", variant="primary")
644
+ output_file_0203 = gr.File(label="输出文件", interactive=False)
645
+
646
+ all_button_0203.click(
647
+ fn=lambda df: gr.Dropdown(value=df["text"].to_list()),
648
+ inputs=[parameters_groups_data_df_state],
649
+ outputs=[parameters_groups_select_0203]
650
+ )
651
+
652
+ use_button_0203a.click(
653
+ fn=updateParametersGroupsDataByCdiFile,
654
+ inputs=[parameters_groups_data_update_file],
655
+ outputs=[parameters_groups_data_dict_state, parameters_groups_data_df_state]
656
+ )
657
+
658
+ process_button_0203b.click(
659
+ fn=processButton0203bClick,
660
+ inputs=[parameters_groups_select_0203, expression_acceptor_file_0203, expression_donor_file_0203, parameters_groups_data_dict_state, parameters_groups_data_df_state],
661
+ outputs=[output_file_0203]
662
+ )
663
+
664
+ clear_button_0203b.click(
665
+ fn=lambda:[[], None, None],
666
+ outputs=[parameters_groups_select_0203, expression_acceptor_file_0203, expression_donor_file_0203]
667
+ )
668
+
669
+
670
+ with gr.Tab("多表情参数迁移叠加"):
671
+
672
+ expression_data_temp_list_state = gr.State([{"Type": "Live2D Expression", "Parameters": []}])
673
+
674
+ gr.Markdown("此工具不再限定参数来源为一个参数施主文件和一个参数受主文件,现在可以将多个表情里指定的参数迁移到目标中。")
675
+ gr.Markdown("新表情的参数会覆盖原有的同名参数,目前有『迁移』『叠加』两种操作。<br>『迁移』和之前一样会删掉参考列表中原表情有而新表情没有的参数,『叠加』则不会。<br>当参数列表包含所有相关参数时,其『迁移』结果新表情将会完全覆盖原表情,『叠加』结果则类似于VTS的表情叠加。")
676
+ gr.Markdown("右侧可预览暂存的表情数据,点击保存按钮可将其保存为json文件。<br>可以撤回处理操作,目前至多支持16步。")
677
+
678
+ with gr.Row():
679
+ with gr.Column(scale=1):
680
+ gr.Markdown("#### 表情参数迁移")
681
+ gr.Markdown("上传参数施主文件并选择参数分组。")
682
+ expression_donor_files = gr.Files(file_types=[".json"], label="上传参数施主文件", interactive=True)
683
+ parameters_groups_select_0204 = gr.Dropdown(choices=parameters_groups_data_df_state.value["text"].to_list(), value=None, multiselect=True, interactive=True, label="选择参数分组")
684
+ with gr.Row():
685
+ all_button_0204a = gr.Button("全选", variant="primary")
686
+ clear_button_0204a = gr.Button("清空", variant="primary")
687
+ with gr.Row():
688
+ migration_button_0204a = gr.Button("迁移", variant="primary")
689
+ overlay_button_0204a = gr.Button("叠加", variant="primary")
690
+
691
+ gr.Markdown("#### 参数分组数据更新")
692
+ gr.Markdown("默认使用现有参数分组数据<br>可上传『.cdi3.json』文件以更新参数分组数据")
693
+ parameters_groups_data_update_file_0204 = gr.File(file_types=[".json"], show_label=False, interactive=True)
694
+ with gr.Row():
695
+ use_button_0204 = gr.Button("更新参数分组", variant="primary")
696
+
697
+ with gr.Column(scale=1):
698
+ expression_data_temp_preview_json = gr.JSON(value=expression_data_temp_list_state.value[-1], label="暂存表情数据预览")
699
+ with gr.Row():
700
+ back_button_0204b = gr.Button("撤回", variant="primary", interactive=False)
701
+ clear_button_0204b = gr.Button("清空", variant="primary")
702
+ save_button_0204b = gr.Button("保存", variant="primary")
703
+ output_file_0204 = gr.File(label="输出文件", interactive=False)
704
+
705
+ all_button_0204a.click(
706
+ fn=lambda df: gr.Dropdown(value=df["text"].to_list()),
707
+ inputs=[parameters_groups_data_df_state],
708
+ outputs=[parameters_groups_select_0204]
709
+ )
710
+
711
+ clear_button_0204a.click(
712
+ fn=lambda :[[], []],
713
+ outputs=[expression_donor_files, parameters_groups_select_0204]
714
+ )
715
+
716
+ migration_button_0204a.click(
717
+ fn=multipleExpressionsParametersMigration,
718
+ inputs=[expression_donor_files, parameters_groups_select_0204, expression_data_temp_list_state, parameters_groups_data_dict_state, parameters_groups_data_df_state],
719
+ outputs=[expression_data_temp_list_state]
720
+ )
721
+
722
+ overlay_button_0204a.click(
723
+ fn=multipleExpressionsParametersOverlay,
724
+ inputs=[expression_donor_files, parameters_groups_select_0204, expression_data_temp_list_state, parameters_groups_data_dict_state, parameters_groups_data_df_state],
725
+ outputs=[expression_data_temp_list_state]
726
+ )
727
+
728
+ use_button_0204.click(
729
+ fn=updateParametersGroupsDataByCdiFile,
730
+ inputs=[parameters_groups_data_update_file_0204],
731
+ outputs=[parameters_groups_data_dict_state, parameters_groups_data_df_state]
732
+ )
733
+
734
+ back_button_0204b.click(
735
+ fn=lambda lst: lst[:-1],
736
+ inputs=[expression_data_temp_list_state],
737
+ outputs=[expression_data_temp_list_state]
738
+ )
739
+
740
+ clear_button_0204b.click(
741
+ fn=expressionDataTempListAppendEmptyExpressionsDict,
742
+ inputs=[expression_data_temp_list_state],
743
+ outputs=[expression_data_temp_list_state]
744
+ )
745
+
746
+ save_button_0204b.click(
747
+ fn=saveButton0204bClick,
748
+ inputs=[expression_data_temp_list_state],
749
+ outputs=[output_file_0204]
750
+ )
751
+
752
+ expression_data_temp_list_state.change(
753
+ fn=expressionDataTempListStateChange,
754
+ inputs=[expression_data_temp_list_state],
755
+ outputs=[expression_data_temp_preview_json, back_button_0204b]
756
+ )
757
+
758
+ ## ???
759
+ parameters_groups_data_df_state.change(
760
+ fn=lambda df: (gr.Dropdown(choices=df["text"].to_list()), gr.Dropdown(choices=df["text"].to_list())),
761
+ inputs=[parameters_groups_data_df_state],
762
+ outputs=[parameters_groups_select_0203, parameters_groups_select_0204]
763
+ )
764
+
765
+
766
 
767
+
768
 
769
 
770
  demo.launch()
requirements.txt CHANGED
@@ -1 +1,3 @@
1
- gradio
 
 
 
1
+ gradio
2
+ numpy
3
+ pandas