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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +219 -59
app.py CHANGED
@@ -101,21 +101,65 @@ custom_css = """
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,7 +175,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
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,9 +183,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
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,35 +193,77 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
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,15 +278,12 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
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,70 +291,151 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
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
  # 启动
 
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
  label="通用标签阈值", info="越高→标签更少更准")
176
  char_slider = gr.Slider(0, 1, 0.85,
177
  label="角色标签阈值", info="推荐保持较高阈值")
 
178
 
179
  gr.Markdown("### 汇总设置")
180
  with gr.Row():
 
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
  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
  "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
  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
  # 启动