IdlecloudX commited on
Commit
1eb8a26
·
verified ·
1 Parent(s): fcaf260

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -220
app.py CHANGED
@@ -9,7 +9,7 @@ from translator import translate_texts
9
  # ------------------------------------------------------------------
10
  # 模型配置
11
  # ------------------------------------------------------------------
12
- MODEL_REPO = "SmilingWolf/wd-swinv2-tagger-v3"
13
  MODEL_FILENAME = "model.onnx"
14
  LABEL_FILENAME = "selected_tags.csv"
15
 
@@ -101,65 +101,21 @@ custom_css = """
101
  padding: 2px 5px;
102
  border-radius: 3px;
103
  background-color: #fff;
104
- cursor: pointer;
105
- transition: background-color 0.2s;
106
  }
107
- .tag-item:hover {
108
- background-color: #e8f4ff;
109
- }
110
- .tag-item:active {
111
- background-color: #bde0ff;
112
- }
113
- .tag-content {
114
- display: flex;
115
- align-items: center;
116
- gap: 10px;
117
- flex: 1;
118
- }
119
- .tag-text {
120
  font-weight: bold;
121
  color: #333;
122
  }
 
 
 
 
123
  .tag-score {
124
  color: #999;
125
  font-size: 0.9em;
126
  }
127
- .copy-container {
128
- position: relative;
129
- margin-bottom: 5px;
130
- }
131
- .copy-button {
132
- position: absolute;
133
- top: 5px;
134
- right: 5px;
135
- padding: 4px 8px;
136
- font-size: 12px;
137
- background-color: #f0f0f0;
138
- border: 1px solid #ddd;
139
- border-radius: 4px;
140
- cursor: pointer;
141
- transition: all 0.2s;
142
- }
143
- .copy-button:hover {
144
- background-color: #e0e0e0;
145
- }
146
- .copy-button:active {
147
- background-color: #d0d0d0;
148
- }
149
- .toast {
150
- position: fixed;
151
- top: 20px;
152
- right: 20px;
153
- padding: 10px 20px;
154
- background-color: #4CAF50;
155
- color: white;
156
- border-radius: 4px;
157
- opacity: 0;
158
- transition: opacity 0.3s;
159
- z-index: 1000;
160
- }
161
- .toast.show {
162
- opacity: 1;
163
  }
164
  """
165
 
@@ -175,6 +131,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
175
  label="通用标签阈值", info="越高→标签更少更准")
176
  char_slider = gr.Slider(0, 1, 0.85,
177
  label="角色标签阈值", info="推荐保持较高阈值")
 
178
 
179
  gr.Markdown("### 汇总设置")
180
  with gr.Row():
@@ -183,6 +140,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
183
  sum_rating = gr.Checkbox(False, label="评分标签")
184
  sum_sep = gr.Dropdown(["逗号", "换行", "空格"], value="逗号", label="分隔符")
185
 
 
 
 
186
  with gr.Column(scale=2):
187
  with gr.Tabs():
188
  with gr.TabItem("🏷️ 通用标签"):
@@ -193,77 +153,35 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
193
  out_rating = gr.HTML(label="Rating Tags")
194
 
195
  gr.Markdown("### 标签汇总")
196
- with gr.Row():
197
- lang_btn = gr.Button("中/EN", variant="secondary", scale=0)
198
- copy_btn = gr.Button("📋 复制", variant="secondary", scale=0)
199
-
200
  out_summary = gr.Textbox(label="标签汇总",
201
  placeholder="选择需要汇总的标签类别...",
202
- lines=3,
203
- interactive=False)
204
-
205
- with gr.Row():
206
- processing_info = gr.Markdown("", visible=False)
207
- btn = gr.Button("开始分析", variant="primary", scale=0)
208
-
209
- # 存储状态的隐藏组件
210
- lang_state = gr.State("en") # 默认显示英文
211
- tags_data = gr.State({}) # 存储标签数据
212
- translations_data = gr.State({}) # 存储翻译数据
213
 
214
  # ----------------- 处理回调 -----------------
215
- def format_tags_html(tags_dict, translations, category_key, current_lang):
216
  """格式化标签为HTML格式"""
217
  if not tags_dict:
218
  return "<p>暂无标签</p>"
219
 
220
  html = '<div class="label-container">'
221
  for i, (tag, score) in enumerate(tags_dict.items()):
222
- display_text = translations[i] if current_lang == "zh" and i < len(translations) else tag
223
- tag_html = f'''
224
- <div class="tag-item" onclick="copyToClipboard('{tag}', '{category_key}_{i}')">
225
- <div class="tag-content">
226
- <span class="tag-text">{display_text}</span>
227
- </div>
228
- <span class="tag-score">{score:.3f}</span>
229
- </div>
230
- '''
231
  html += tag_html
232
  html += '</div>'
233
-
234
- # 添加复制函数的JavaScript
235
- copy_script = '''
236
- <script>
237
- function copyToClipboard(text, itemId) {
238
- navigator.clipboard.writeText(text).then(function() {
239
- showToast('已复制: ' + text);
240
- });
241
- }
242
-
243
- function showToast(message) {
244
- var toast = document.createElement('div');
245
- toast.className = 'toast show';
246
- toast.textContent = message;
247
- document.body.appendChild(toast);
248
-
249
- setTimeout(function() {
250
- toast.classList.remove('show');
251
- setTimeout(function() {
252
- document.body.removeChild(toast);
253
- }, 300);
254
- }, 1500);
255
- }
256
- </script>
257
- '''
258
-
259
- return html + copy_script
260
 
261
- def process(img, g_th, c_th, sum_gen, sum_char, sum_rat, sep_type, current_lang, prev_tags, prev_translations):
262
- # 开始处理
263
  yield (
264
  gr.update(interactive=False, value="处理中..."),
265
  gr.update(visible=True, value="🔄 正在分析图像..."),
266
- "", "", "", "", current_lang, {}, {}
267
  )
268
 
269
  try:
@@ -278,12 +196,15 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
278
  "ratings": list(res["ratings"].keys())
279
  }
280
 
281
- for tags in tag_categories.values():
282
- all_tags.extend(tags)
283
-
284
- # 批量翻译
285
- if all_tags:
286
- translations = translate_texts(all_tags, src_lang="auto", tgt_lang="zh")
 
 
 
287
  else:
288
  translations = []
289
 
@@ -291,151 +212,70 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
291
  translations_dict = {}
292
  offset = 0
293
  for category, tags in tag_categories.items():
294
- if tags:
295
  translations_dict[category] = translations[offset:offset+len(tags)]
296
  offset += len(tags)
297
  else:
298
  translations_dict[category] = []
299
 
300
  # 生成HTML输出
301
- general_html = format_tags_html(res["general"], translations_dict["general"], "general", current_lang)
302
- char_html = format_tags_html(res["characters"], translations_dict["characters"], "characters", current_lang)
303
- rating_html = format_tags_html(res["ratings"], translations_dict["ratings"], "ratings", current_lang)
304
 
305
  # 生成汇总文本
306
- summary_tags = []
307
  separators = {"逗号": ", ", "换行": "\n", "空格": " "}
308
  separator = separators[sep_type]
309
 
310
- # 按顺序:角色、通用、评分
311
- if sum_char and res["characters"]:
312
- if current_lang == "zh" and translations_dict["characters"]:
313
- summary_tags.extend(translations_dict["characters"])
314
  else:
315
- summary_tags.extend(list(res["characters"].keys()))
 
316
 
317
- if sum_gen and res["general"]:
318
- if current_lang == "zh" and translations_dict["general"]:
319
- summary_tags.extend(translations_dict["general"])
320
  else:
321
- summary_tags.extend(list(res["general"].keys()))
 
322
 
323
  if sum_rat and res["ratings"]:
324
- if current_lang == "zh" and translations_dict["ratings"]:
325
- summary_tags.extend(translations_dict["ratings"])
326
  else:
327
- summary_tags.extend(list(res["ratings"].keys()))
 
328
 
329
- summary_text = separator.join(summary_tags) if summary_tags else "请选择要汇总的标签类别"
330
 
331
- # 完成处理
332
  yield (
333
  gr.update(interactive=True, value="开始分析"),
334
  gr.update(visible=False),
335
  general_html,
336
  char_html,
337
  rating_html,
338
- summary_text,
339
- current_lang,
340
- res,
341
- translations_dict
342
  )
343
 
344
  except Exception as e:
345
- # 出错处理
346
  yield (
347
  gr.update(interactive=True, value="开始分析"),
348
  gr.update(visible=True, value=f"❌ 处理失败: {str(e)}"),
349
- "", "", "", "", current_lang, {}, {}
350
  )
351
 
352
- def toggle_language(current_lang, tags, translations):
353
- """切换语言显示"""
354
- new_lang = "zh" if current_lang == "en" else "en"
355
-
356
- # 重新生成HTML
357
- general_html = format_tags_html(tags.get("general", {}), translations.get("general", []), "general", new_lang)
358
- char_html = format_tags_html(tags.get("characters", {}), translations.get("characters", []), "characters", new_lang)
359
- rating_html = format_tags_html(tags.get("ratings", {}), translations.get("ratings", []), "ratings", new_lang)
360
-
361
- # 更新汇总文本
362
- current_summary = out_summary.value if hasattr(out_summary, 'value') else ""
363
- if current_summary and current_summary != "请选择要汇总的标签类别":
364
- # 需要重新生成汇总文本
365
- summary_tags = []
366
- separator = ", " # 这里简化,实际应该记住用户选择的分隔符
367
-
368
- # 检查选择的类别并生成汇总
369
- # 注意:这里只是示例,实际需要传入选择状态
370
- for category, category_tags in tags.items():
371
- if category_tags:
372
- if new_lang == "zh" and translations.get(category):
373
- summary_tags.extend(translations[category])
374
- else:
375
- summary_tags.extend(list(category_tags.keys()))
376
-
377
- summary_text = separator.join(summary_tags) if summary_tags else current_summary
378
- else:
379
- summary_text = current_summary
380
-
381
- return (
382
- new_lang,
383
- general_html,
384
- char_html,
385
- rating_html,
386
- summary_text
387
- )
388
-
389
- def copy_summary(text):
390
- """提示复制汇总文本"""
391
- # 使用JavaScript来复制文本
392
- copy_js = f'''
393
- <script>
394
- navigator.clipboard.writeText(`{text}`).then(function() {{
395
- showCopyToast('标签已复制到剪贴板');
396
- }});
397
-
398
- function showCopyToast(message) {{
399
- var toast = document.createElement('div');
400
- toast.className = 'toast show';
401
- toast.textContent = message;
402
- toast.style.position = 'fixed';
403
- toast.style.top = '20px';
404
- toast.style.right = '20px';
405
- toast.style.padding = '10px 20px';
406
- toast.style.backgroundColor = '#4CAF50';
407
- toast.style.color = 'white';
408
- toast.style.borderRadius = '4px';
409
- toast.style.zIndex = '1000';
410
- document.body.appendChild(toast);
411
-
412
- setTimeout(function() {{
413
- toast.remove();
414
- }}, 1500);
415
- }}
416
- </script>
417
- '''
418
- return gr.update(value=copy_js)
419
-
420
  # 绑定事件
421
  btn.click(
422
  process,
423
- inputs=[img_in, gen_slider, char_slider, sum_general, sum_char, sum_rating, sum_sep, lang_state, tags_data, translations_data],
424
- outputs=[btn, processing_info, out_general, out_char, out_rating, out_summary, lang_state, tags_data, translations_data],
425
  show_progress=True
426
  )
427
-
428
- lang_btn.click(
429
- toggle_language,
430
- inputs=[lang_state, tags_data, translations_data],
431
- outputs=[lang_state, out_general, out_char, out_rating, out_summary]
432
- )
433
-
434
- copy_btn.click(
435
- copy_summary,
436
- inputs=[out_summary],
437
- outputs=[gr.HTML(visible=False)]
438
- )
439
 
440
  # ------------------------------------------------------------------
441
  # 启动
 
9
  # ------------------------------------------------------------------
10
  # 模型配置
11
  # ------------------------------------------------------------------
12
+ MODEL_REPO = "SmilingWolf/wd-eva02-large-tagger-v3"
13
  MODEL_FILENAME = "model.onnx"
14
  LABEL_FILENAME = "selected_tags.csv"
15
 
 
101
  padding: 2px 5px;
102
  border-radius: 3px;
103
  background-color: #fff;
 
 
104
  }
105
+ .tag-en {
 
 
 
 
 
 
 
 
 
 
 
 
106
  font-weight: bold;
107
  color: #333;
108
  }
109
+ .tag-zh {
110
+ color: #666;
111
+ margin-left: 10px;
112
+ }
113
  .tag-score {
114
  color: #999;
115
  font-size: 0.9em;
116
  }
117
+ .btn-container {
118
+ margin-top: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
  """
121
 
 
131
  label="通用标签阈值", info="越高→标签更少更准")
132
  char_slider = gr.Slider(0, 1, 0.85,
133
  label="角色标签阈值", info="推荐保持较高阈值")
134
+ show_zh = gr.Checkbox(True, label="显示中文翻译")
135
 
136
  gr.Markdown("### 汇总设置")
137
  with gr.Row():
 
140
  sum_rating = gr.Checkbox(False, label="评分标签")
141
  sum_sep = gr.Dropdown(["逗号", "换行", "空格"], value="逗号", label="分隔符")
142
 
143
+ btn = gr.Button("开始分析", variant="primary", elem_classes=["btn-container"])
144
+ processing_info = gr.Markdown("", visible=False)
145
+
146
  with gr.Column(scale=2):
147
  with gr.Tabs():
148
  with gr.TabItem("🏷️ 通用标签"):
 
153
  out_rating = gr.HTML(label="Rating Tags")
154
 
155
  gr.Markdown("### 标签汇总")
 
 
 
 
156
  out_summary = gr.Textbox(label="标签汇总",
157
  placeholder="选择需要汇总的标签类别...",
158
+ lines=3)
 
 
 
 
 
 
 
 
 
 
159
 
160
  # ----------------- 处理回调 -----------------
161
+ def format_tags_html(tags_dict, translations, show_translation=True):
162
  """格式化标签为HTML格式"""
163
  if not tags_dict:
164
  return "<p>暂无标签</p>"
165
 
166
  html = '<div class="label-container">'
167
  for i, (tag, score) in enumerate(tags_dict.items()):
168
+ tag_html = f'<div class="tag-item">'
169
+ tag_html += f'<div><span class="tag-en">{tag}</span>'
170
+ if show_translation and i < len(translations):
171
+ tag_html += f'<span class="tag-zh">({translations[i]})</span>'
172
+ tag_html += '</div>'
173
+ tag_html += f'<span class="tag-score">{score:.3f}</span>'
174
+ tag_html += '</div>'
 
 
175
  html += tag_html
176
  html += '</div>'
177
+ return html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
+ def process(img, g_th, c_th, show_zh, sum_gen, sum_char, sum_rat, sep_type):
180
+ # 开始处理,返回更新
181
  yield (
182
  gr.update(interactive=False, value="处理中..."),
183
  gr.update(visible=True, value="🔄 正在分析图像..."),
184
+ "", "", "", ""
185
  )
186
 
187
  try:
 
196
  "ratings": list(res["ratings"].keys())
197
  }
198
 
199
+ if show_zh:
200
+ for tags in tag_categories.values():
201
+ all_tags.extend(tags)
202
+
203
+ # 批量翻译
204
+ if all_tags:
205
+ translations = translate_texts(all_tags, src_lang="auto", tgt_lang="zh")
206
+ else:
207
+ translations = []
208
  else:
209
  translations = []
210
 
 
212
  translations_dict = {}
213
  offset = 0
214
  for category, tags in tag_categories.items():
215
+ if show_zh and tags:
216
  translations_dict[category] = translations[offset:offset+len(tags)]
217
  offset += len(tags)
218
  else:
219
  translations_dict[category] = []
220
 
221
  # 生成HTML输出
222
+ general_html = format_tags_html(res["general"], translations_dict["general"], show_zh)
223
+ char_html = format_tags_html(res["characters"], translations_dict["characters"], show_zh)
224
+ rating_html = format_tags_html(res["ratings"], translations_dict["ratings"], show_zh)
225
 
226
  # 生成汇总文本
227
+ summary_parts = []
228
  separators = {"逗号": ", ", "换行": "\n", "空格": " "}
229
  separator = separators[sep_type]
230
 
231
+ if sum_gen and res["general"]:
232
+ if show_zh and translations_dict["general"]:
233
+ gen_tags = [f"{en}({zh})" for en, zh in zip(res["general"].keys(), translations_dict["general"])]
 
234
  else:
235
+ gen_tags = list(res["general"].keys())
236
+ summary_parts.append("通用标签: " + separator.join(gen_tags))
237
 
238
+ if sum_char and res["characters"]:
239
+ if show_zh and translations_dict["characters"]:
240
+ char_tags = [f"{en}({zh})" for en, zh in zip(res["characters"].keys(), translations_dict["characters"])]
241
  else:
242
+ char_tags = list(res["characters"].keys())
243
+ summary_parts.append("角色标签: " + separator.join(char_tags))
244
 
245
  if sum_rat and res["ratings"]:
246
+ if show_zh and translations_dict["ratings"]:
247
+ rat_tags = [f"{en}({zh})" for en, zh in zip(res["ratings"].keys(), translations_dict["ratings"])]
248
  else:
249
+ rat_tags = list(res["ratings"].keys())
250
+ summary_parts.append("评分标签: " + separator.join(rat_tags))
251
 
252
+ summary_text = "\n\n".join(summary_parts) if summary_parts else "请选择要汇总的标签类别"
253
 
254
+ # 完成处理,返回最终结果
255
  yield (
256
  gr.update(interactive=True, value="开始分析"),
257
  gr.update(visible=False),
258
  general_html,
259
  char_html,
260
  rating_html,
261
+ summary_text
 
 
 
262
  )
263
 
264
  except Exception as e:
265
+ # 出错时的处理
266
  yield (
267
  gr.update(interactive=True, value="开始分析"),
268
  gr.update(visible=True, value=f"❌ 处理失败: {str(e)}"),
269
+ "", "", "", ""
270
  )
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  # 绑定事件
273
  btn.click(
274
  process,
275
+ inputs=[img_in, gen_slider, char_slider, show_zh, sum_general, sum_char, sum_rating, sum_sep],
276
+ outputs=[btn, processing_info, out_general, out_char, out_rating, out_summary],
277
  show_progress=True
278
  )
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
  # ------------------------------------------------------------------
281
  # 启动