Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -58,8 +58,6 @@ class Tagger:
|
|
| 58 |
print(f"❌ 模型或标签加载失败: {e}")
|
| 59 |
raise RuntimeError(f"模型初始化失败: {e}")
|
| 60 |
|
| 61 |
-
|
| 62 |
-
# ------------------------- preprocess -------------------------
|
| 63 |
def _preprocess(self, img: Image.Image) -> np.ndarray:
|
| 64 |
if img is None:
|
| 65 |
raise ValueError("输入图像不能为空")
|
|
@@ -72,7 +70,6 @@ class Tagger:
|
|
| 72 |
canvas = canvas.resize((self.input_size, self.input_size), Image.BICUBIC)
|
| 73 |
return np.array(canvas)[:, :, ::-1].astype(np.float32) # to BGR
|
| 74 |
|
| 75 |
-
# --------------------------- predict --------------------------
|
| 76 |
def predict(self, img: Image.Image, gen_th: float = 0.35, char_th: float = 0.85):
|
| 77 |
if self.model is None:
|
| 78 |
raise RuntimeError("模型未成功加载,无法进行预测。")
|
|
@@ -164,25 +161,21 @@ custom_css = """
|
|
| 164 |
|
| 165 |
_js_functions = """
|
| 166 |
function copyToClipboard(text) {
|
| 167 |
-
// --- 调试信息 ---
|
| 168 |
console.log('copyToClipboard function was called.');
|
| 169 |
console.log('Received text:', text);
|
| 170 |
-
// console.trace(); // 如果需要更详细的调用栈信息,可以取消这行注释
|
| 171 |
|
| 172 |
-
//
|
| 173 |
-
// 如果 text 未定义或为 null,则不执行后续操作,并打印警告
|
| 174 |
if (typeof text === 'undefined' || text === null) {
|
| 175 |
console.warn('copyToClipboard was called with undefined or null text. Aborting this specific copy operation.');
|
| 176 |
-
// 在这种情况下,我们不应该尝试复制,也不应该显示“已复制”的提示
|
| 177 |
return;
|
| 178 |
}
|
| 179 |
|
| 180 |
navigator.clipboard.writeText(text).then(() => {
|
| 181 |
-
// console.log('Tag copied to clipboard: ' + text);
|
| 182 |
const feedback = document.createElement('div');
|
| 183 |
|
| 184 |
// 确保 text 是字符串类型,再进行 substring 操作
|
| 185 |
-
let displayText = String(text);
|
| 186 |
displayText = displayText.substring(0, 30) + (displayText.length > 30 ? '...' : '');
|
| 187 |
|
| 188 |
feedback.textContent = '已复制: ' + displayText;
|
|
@@ -207,15 +200,13 @@ function copyToClipboard(text) {
|
|
| 207 |
}, 1500);
|
| 208 |
}).catch(err => {
|
| 209 |
console.error('Failed to copy tag. Error:', err, 'Attempted to copy text:', text);
|
| 210 |
-
// 可以考虑也给用户一个错误提示,但原版 alert 可能体验不佳
|
| 211 |
-
// alert('复制失败: ' + err);
|
| 212 |
const errorFeedback = document.createElement('div');
|
| 213 |
-
errorFeedback.textContent = '复制操作失败!';
|
| 214 |
errorFeedback.style.position = 'fixed';
|
| 215 |
errorFeedback.style.bottom = '20px';
|
| 216 |
errorFeedback.style.left = '50%';
|
| 217 |
errorFeedback.style.transform = 'translateX(-50%)';
|
| 218 |
-
errorFeedback.style.backgroundColor = '#D32F2F';
|
| 219 |
errorFeedback.style.color = 'white';
|
| 220 |
errorFeedback.style.padding = '10px 20px';
|
| 221 |
errorFeedback.style.borderRadius = '5px';
|
|
@@ -339,20 +330,18 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 339 |
|
| 340 |
for i, en_tag in enumerate(cat_tags_en):
|
| 341 |
if s_show_zh and i < len(cat_translations) and cat_translations[i]:
|
| 342 |
-
tags_to_join.append(f"{en_tag}
|
| 343 |
else:
|
| 344 |
tags_to_join.append(en_tag)
|
| 345 |
if tags_to_join: # only add if there are tags for this category
|
| 346 |
summary_parts.append(separator.join(tags_to_join))
|
| 347 |
|
| 348 |
-
# Join parts with double newline for readability if multiple categories present and separator is not newline
|
| 349 |
joiner = "\n\n" if separator != "\n" and len(summary_parts) > 1 else separator if separator == "\n" else " "
|
| 350 |
|
| 351 |
final_summary = joiner.join(summary_parts)
|
| 352 |
return final_summary if final_summary else "选定的类别中没有找到标签。"
|
| 353 |
|
| 354 |
|
| 355 |
-
# ----------------- 主要处理回调 -----------------
|
| 356 |
def process_image_and_generate_outputs(
|
| 357 |
img, g_th, c_th, s_scores, # Main inputs
|
| 358 |
s_gen, s_char, s_rat, s_sep, s_zh_in_sum
|
|
@@ -388,7 +377,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 388 |
)
|
| 389 |
|
| 390 |
try:
|
| 391 |
-
# 1. Predict tags
|
| 392 |
res, tag_categories_original_order = tagger_instance.predict(img, g_th, c_th)
|
| 393 |
|
| 394 |
all_tags_to_translate = []
|
|
@@ -443,7 +431,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 443 |
{}, {}, {}
|
| 444 |
)
|
| 445 |
|
| 446 |
-
# ----------------- 更新汇总文本的回调 -----------------
|
| 447 |
def update_summary_display(
|
| 448 |
s_gen, s_char, s_rat, s_sep, s_zh_in_sum,
|
| 449 |
current_res_from_state, current_translations_from_state
|
|
@@ -457,7 +444,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 457 |
)
|
| 458 |
return gr.update(value=new_summary_text)
|
| 459 |
|
| 460 |
-
# ----------------- 绑定事件 -----------------
|
| 461 |
btn.click(
|
| 462 |
process_image_and_generate_outputs,
|
| 463 |
inputs=[
|
|
@@ -470,7 +456,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 470 |
out_summary,
|
| 471 |
state_res, state_translations_dict, state_tag_categories_for_translation
|
| 472 |
],
|
| 473 |
-
# show_progress="full" # Gradio's built-in progress
|
| 474 |
)
|
| 475 |
|
| 476 |
summary_controls = [sum_general, sum_char, sum_rating, sum_sep, sum_show_zh]
|
|
@@ -479,12 +464,8 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI 图像标签分析器", css=cus
|
|
| 479 |
fn=update_summary_display,
|
| 480 |
inputs=summary_controls + [state_res, state_translations_dict],
|
| 481 |
outputs=[out_summary],
|
| 482 |
-
# show_progress=False # Typically fast, no need for progress indicator
|
| 483 |
)
|
| 484 |
-
|
| 485 |
-
# ------------------------------------------------------------------
|
| 486 |
-
# 启动
|
| 487 |
-
# ------------------------------------------------------------------
|
| 488 |
if __name__ == "__main__":
|
| 489 |
if tagger_instance is None:
|
| 490 |
print("CRITICAL: Tagger 未能初始化,应用功能将受限。请检查之前的错误信息。")
|
|
|
|
| 58 |
print(f"❌ 模型或标签加载失败: {e}")
|
| 59 |
raise RuntimeError(f"模型初始化失败: {e}")
|
| 60 |
|
|
|
|
|
|
|
| 61 |
def _preprocess(self, img: Image.Image) -> np.ndarray:
|
| 62 |
if img is None:
|
| 63 |
raise ValueError("输入图像不能为空")
|
|
|
|
| 70 |
canvas = canvas.resize((self.input_size, self.input_size), Image.BICUBIC)
|
| 71 |
return np.array(canvas)[:, :, ::-1].astype(np.float32) # to BGR
|
| 72 |
|
|
|
|
| 73 |
def predict(self, img: Image.Image, gen_th: float = 0.35, char_th: float = 0.85):
|
| 74 |
if self.model is None:
|
| 75 |
raise RuntimeError("模型未成功加载,无法进行预测。")
|
|
|
|
| 161 |
|
| 162 |
_js_functions = """
|
| 163 |
function copyToClipboard(text) {
|
|
|
|
| 164 |
console.log('copyToClipboard function was called.');
|
| 165 |
console.log('Received text:', text);
|
|
|
|
| 166 |
|
| 167 |
+
// 如果 text 未定义或为 null
|
|
|
|
| 168 |
if (typeof text === 'undefined' || text === null) {
|
| 169 |
console.warn('copyToClipboard was called with undefined or null text. Aborting this specific copy operation.');
|
|
|
|
| 170 |
return;
|
| 171 |
}
|
| 172 |
|
| 173 |
navigator.clipboard.writeText(text).then(() => {
|
| 174 |
+
// console.log('Tag copied to clipboard: ' + text);
|
| 175 |
const feedback = document.createElement('div');
|
| 176 |
|
| 177 |
// 确保 text 是字符串类型,再进行 substring 操作
|
| 178 |
+
let displayText = String(text);
|
| 179 |
displayText = displayText.substring(0, 30) + (displayText.length > 30 ? '...' : '');
|
| 180 |
|
| 181 |
feedback.textContent = '已复制: ' + displayText;
|
|
|
|
| 200 |
}, 1500);
|
| 201 |
}).catch(err => {
|
| 202 |
console.error('Failed to copy tag. Error:', err, 'Attempted to copy text:', text);
|
|
|
|
|
|
|
| 203 |
const errorFeedback = document.createElement('div');
|
| 204 |
+
errorFeedback.textContent = '复制操作失败!';
|
| 205 |
errorFeedback.style.position = 'fixed';
|
| 206 |
errorFeedback.style.bottom = '20px';
|
| 207 |
errorFeedback.style.left = '50%';
|
| 208 |
errorFeedback.style.transform = 'translateX(-50%)';
|
| 209 |
+
errorFeedback.style.backgroundColor = '#D32F2F';
|
| 210 |
errorFeedback.style.color = 'white';
|
| 211 |
errorFeedback.style.padding = '10px 20px';
|
| 212 |
errorFeedback.style.borderRadius = '5px';
|
|
|
|
| 330 |
|
| 331 |
for i, en_tag in enumerate(cat_tags_en):
|
| 332 |
if s_show_zh and i < len(cat_translations) and cat_translations[i]:
|
| 333 |
+
tags_to_join.append(f"{en_tag}/*{cat_translations[i]}*/")
|
| 334 |
else:
|
| 335 |
tags_to_join.append(en_tag)
|
| 336 |
if tags_to_join: # only add if there are tags for this category
|
| 337 |
summary_parts.append(separator.join(tags_to_join))
|
| 338 |
|
|
|
|
| 339 |
joiner = "\n\n" if separator != "\n" and len(summary_parts) > 1 else separator if separator == "\n" else " "
|
| 340 |
|
| 341 |
final_summary = joiner.join(summary_parts)
|
| 342 |
return final_summary if final_summary else "选定的类别中没有找到标签。"
|
| 343 |
|
| 344 |
|
|
|
|
| 345 |
def process_image_and_generate_outputs(
|
| 346 |
img, g_th, c_th, s_scores, # Main inputs
|
| 347 |
s_gen, s_char, s_rat, s_sep, s_zh_in_sum
|
|
|
|
| 377 |
)
|
| 378 |
|
| 379 |
try:
|
|
|
|
| 380 |
res, tag_categories_original_order = tagger_instance.predict(img, g_th, c_th)
|
| 381 |
|
| 382 |
all_tags_to_translate = []
|
|
|
|
| 431 |
{}, {}, {}
|
| 432 |
)
|
| 433 |
|
|
|
|
| 434 |
def update_summary_display(
|
| 435 |
s_gen, s_char, s_rat, s_sep, s_zh_in_sum,
|
| 436 |
current_res_from_state, current_translations_from_state
|
|
|
|
| 444 |
)
|
| 445 |
return gr.update(value=new_summary_text)
|
| 446 |
|
|
|
|
| 447 |
btn.click(
|
| 448 |
process_image_and_generate_outputs,
|
| 449 |
inputs=[
|
|
|
|
| 456 |
out_summary,
|
| 457 |
state_res, state_translations_dict, state_tag_categories_for_translation
|
| 458 |
],
|
|
|
|
| 459 |
)
|
| 460 |
|
| 461 |
summary_controls = [sum_general, sum_char, sum_rating, sum_sep, sum_show_zh]
|
|
|
|
| 464 |
fn=update_summary_display,
|
| 465 |
inputs=summary_controls + [state_res, state_translations_dict],
|
| 466 |
outputs=[out_summary],
|
|
|
|
| 467 |
)
|
| 468 |
+
|
|
|
|
|
|
|
|
|
|
| 469 |
if __name__ == "__main__":
|
| 470 |
if tagger_instance is None:
|
| 471 |
print("CRITICAL: Tagger 未能初始化,应用功能将受限。请检查之前的错误信息。")
|